<http://www.netikka.net/tsneti/info/tscmd014.htm>
Copyright © 2003-2012 by Prof. Timo Salmi  
Last modified Wed 4-Apr-2012 13:59:16

 
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.



14} Help! My old batch files won't work since there is no choice.com

Q: When I try to run my old batch file as a CMD.EXE script I get "'choice' is not recognized as an internal or external command, operable program or batch file." What can I do?

A: The CHOICE command has been dropped because allegedly it can cause collisions in the NT/2000/XP multi-tasking environment. Thus the best choice (if you pardon the pun) is not try to find an old version, but patiently write your scripts anew using SET /P. However, choice is back on Vista. Anyway, below is a simple demonstration of the set /p usage.

  @echo off & setlocal enableextensions
  :_again
  set ask_=
  set /p ask_="Please respond [y,n,q]?"
  for %%a in (y n q) do if /i "%ask_%"=="%%a" goto _%%a
  goto _again
  ::
  :_y
  echo Your input was Yes& goto :EOF
  :_n
  echo Your input was No& goto :EOF
  :_q
  echo Your input was Quit& goto :EOF
  endlocal & goto :EOF

The same with a slightly different logic, and a default.
  @echo off & setlocal enableextensions
  :_again
  set ask_=
  set /p ask_="Please respond [Y,n,q]?"
  if /i "%ask_%"=="q" goto _q
  if /i "%ask_%"=="n" goto _n
  if /i not "%ask_%"=="y" if not "%ask_%"=="" goto _again
  goto _y
  ::
  :_y
  echo Your input was Yes& goto :EOF
  :_n
  echo Your input was No& goto :EOF
  :_q
  echo Your input was Quit& goto :EOF
  endlocal & goto :EOF

The output could be e.g.
  D:\TEST>cmdfaq
  Please respond [Y,n,q]?n
  Your input was No

The line
  set /p ask_="Please respond [Y,n,q]?"
could alternatively be written as
  (set /p ask_=Please respond [Y,n,q]?)

The response could also be written as a subroutine. (The usefulness of the option would become more obvious if the script contained several questions.)
  @echo off & setlocal enableextensions
  Call :AskQuestionWithYdefault "Please respond [Y,n,q]?" reply_
  goto _%reply_%1
  ::
  :_y1
  echo Your input was Yes& goto :EOF
  :_n1
  echo Your input was No& goto :EOF
  :_q1
  echo Your input was Quit& goto :EOF
  endlocal & goto :EOF
  ::
  :: The question as a subroutine

  :AskQuestionWithYdefault
    setlocal enableextensions
    :_askthequestionagain
    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 /i "%ask_%"=="q" set return_=q
    if not defined return_ goto _askthequestionagain
  endlocal & set "%2=%return_%" & goto :EOF

The following version demonstrates the fact that setclocal only makes the environment variables within a setclocal endlocal pair unique, but the same does not go for the labels. Thus the label _askthequestionagain can't appear in both the subroutines without causing confusion. The labels must be unique.
  @echo off & setlocal enableextensions
  Call :AskQuestionWithYdefault "Please respond [Y,n,q]?" reply_
  echo Your first reply: %reply_%
  Call :AskQuestionWithNdefault "Please respond [y,N,q]?" reply_
  echo Your second reply: %reply_%
  endlocal & goto :EOF
  ::
  :: The question as a subroutine

  :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 /i "%ask_%"=="q" set return_=q
    if not defined return_ goto _asktheyquestionagain
  endlocal & set "%2=%return_%" & goto :EOF
  ::
  :AskQuestionWithNdefault
    setlocal enableextensions
    :_askthenquestionagain
    set return_=
    set ask_=
    set /p ask_="%~1"
    if "%ask_%"=="" set return_=n
    if /i "%ask_%"=="y" set return_=y
    if /i "%ask_%"=="n" set return_=n
    if /i "%ask_%"=="q" set return_=q
    if not defined return_ goto _askthenquestionagain
  endlocal & set "%2=%return_%" & goto :EOF
The output could be e.g.
  D:\TEST>cmdfaq
  Please respond [Y,n,q]?q
  Your first reply: q
  Please respond [y,N,q]?x
  Please respond [y,N,q]?
  Your second reply: n

Consider a snippet from a real-life script for "whatever" actual task. If Opera (a browser, as you know) happens to be running, one wants to ensure the user's permission to do the "whatever". Else one just performs the "whatever" outright. Also note the if construct, which requires using delayed expansion. As for the <CTRL-G>, it is the beep, i.e. ASCII 7.
  echo off & setlocal enableextensions enabledelayedexpansion
  tasklist|find /i "opera.exe">nul
  if !errorlevel! EQU 0 (
    echo Opera is running<CTRL-G>
    call :ContinueOrNot reply_
    if "!reply_!"=="n" (endlocal & goto :EOF))
  echo Do here whatever you intend to do
  endlocal & goto :EOF
  ::
  :: The question as a subroutine

  :ContinueOrNot
  setlocal enableextensions
  :_askthequestionagain
  set ask_=
  set /p ask_="Continue nevertheless [y,N]?"
  if /i "%ask_%"=="y" (endlocal & set "%1=y" & goto :EOF)
  if not "%ask_%"=="" if /i not "%ask_%"=="n" goto _askthequestionagain
  endlocal & set "%1=n" & goto :EOF

Anyway, instead of the SET /P you might try a clone such as CHOOSE.EXE "Ask questions in batch/script files" from tsutlf17.zip or later. (Now also included in tscmd.zip)
  @echo off & setlocal enableextensions
  choose /tq,5 /cynq "Give your answer "
  if errorlevel==0 if not errorlevel==1 echo You effected a break
  if errorlevel==1 if not errorlevel==2 echo Your input was Yes
  if errorlevel==2 if not errorlevel==3 echo Your input was No
  if errorlevel==3 if not errorlevel==4 echo Your input was Quit
  if errorlevel==255 echo Error condition
  endlocal & goto :EOF

Alternatively
  @echo off & setlocal enableextensions
  choose /tq,5 /cynq /x "Give your answer "
  for %%c in (call del) do %%c choose_.bat
  if "%choose_%"=="0" echo You effected a break
  if "%choose_%"=="1" echo Your input was Yes
  if "%choose_%"=="2" echo Your input was No
  if "%choose_%"=="3" echo Your input was Quit
  if "%choose_%"=="255" echo Error condition
  endlocal & goto :EOF

The output in both the cases might be e.g.
  D:\TEST>cmdfaq
  Give your answer [Y,N,Q]?Q
  Your input was Quit

The obvious advantage of CHOOSE.EXE over the SET /P method is that the former can handle timed default input.

If you want Microsoft's old CHOICE.EXE it seems to be available from the Microsoft Windows 98 Resource Kit e.g. at ftp://ftp.microsoft.com/Services/TechNet/samples/PS/Win98/Reskit/SCRPTING (For the tools included with the Microsoft Windows 98 Resource Kit see http://support.microsoft.com/kb/247024)


References/Comments: (If a Google message link fails try the links within the brackets.)
  hh ntcmds.chm::/set.htm
  Google Groups Jan 8 2003, 9:01 pm [M]
  CHOICE-Windows Command
  SET-Windows Command