How to start a system "beep", from the built-in pc speaker, using a batch file? - windows

I have written a batch script in an interactive mode, for making some tasks.
Sometimes, These tasks takes a long time to be finished, and then the batch asks if the user wants to go on to the next task, or back to the Batch's Main Menu or... etc
Now, what I want to do, is to add an "Interactive Alarm" command, that sounds a small short beep (Ex: Like the one when we turn on our PCs), to alert the batch user for new questions .
I don't know if this is possible or not, but the most important thing for me, NOT to use a GUI application like WMP or so..
I just want to do this from the Background, even If that beep has to be made from the free speaker, or by using a Third-Party CLI Application (Btw, I've Cygwin installed on my Win7-x64) .
Please note that, I will add that alarm command exactly before the interactive questions, waiting for user's answer to get to the next stage, so I can't just finish the batch, by making a real error beep !
So, would somebody please tell me how to do this ?
Appreciate your help :)

WARNING: rundll32.exe Kernel32.dll,Beep 750,300 no longer works well from the command line on modern windows systems as rundll32 no longer accepts integer values (again, through the command line) and this will play the beep with the default values which is too long (and frequency is irritating):
REM Again, with warnings about running this from the command line...
rundll32.exe Kernel32.dll,Beep 750,300
or
rundll32.exe cmdext.dll,MessageBeepStub
or
rundll32 user32.dll,MessageBeep
With rundll functions you won't need special symbols like ^G. With the first method you can also set the frequency and the time you want to beep, though see the warning that those parameters no longer work on modern systems from the command line and will instead play the annoying defaults.
UPDATE
other options are:
powershell "[console]::beep(500,300)"
or using systemSounds.bat
call systemsounds.bat beep
The capability of beeping depends on the mainboard and if the mainboard has a system speaker - which has increasingly become a rarity as systems tend to depend solely on "normal" speakers instead. An alternative is to play sound through those speakers. Here are some options:
Using the speaking capabilities of the SAPI.SpVoice:
mshta "javascript:code(close((V=(v=new ActiveXObject('SAPI.SpVoice')).GetVoices()).count&&v.Speak('beep')))"
Here this is wrapped in a batch file and the words can be passed as an argument.
SAPI.SpVoice can be used for playing wav files and you have some packaged with the default Windows installation. You can use this script:
spplayer.bat "C:\Windows\Media\Windows Navigation Start.wav"
Another option: Using the windows media player active-x objects to play a sound. On Windows XP it was not installed by default but I think for the newer Windows versions it is. It also can play mp3 files:
call mediarunner.bat "C:\Windows\Media\Ring03.wav"
And one that is a little bit obscure - using the <bgsound> tag from internet explorer (which also can play mp3 files). Here's the script:
call soundplayer.bat "C:\Windows\Media\tada.wav"
And here's a way to use the BEL character to produce sound with easy to copy-paste code (I've called it a beeper.bat):
#echo off
setlocal
::Define a Linefeed variable
(set LF=^
%=-=%
)
for /f eol^=^%LF%%LF%^ delims^= %%A in (
'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x07"'
) do echo(%%A

It's not possible to type the BEL directly in (for example) notepad.
To get it, type echo ^G>>yourbatch.bat on the command line (don't type ^ G, but <Control>-G, which will be shown as ^G on the screen). That puts a strange looking character to the end of your file. That's the BELcharacter 0x007 ("control-G"). Just copy/move it to any echo command, you like. Also
set /p "input=^Ggive value: "
is possible (where the ^G represents that strange char)

The following can be used to issue a beep
without pausing the script
without creating a new line.
without requiring the use of a non-printable character
Echo/| CHOICE /N 2> nul & rem BEL
It is a deliberate misuse of the choice command, that Echo's nothing via a pipe to Choice, causing a non-breaking error. STDERR is redirected to nul, and the default choice prompt is suppressed via the /N switch, meaning no new line is output.
If for some reason you wanted to reuse this annoying tone throughout a script, you could define it as a macro
Set "BEL=Echo/| CHOICE /N 2> nul"
%BEL%

#echo off
echo BEEP.BAT by CSS---
echo PRESS ANY KEY TO HEAR A BEEP...
PAUSE>NUL
ECHO
echo I BEEPED
PAUSE
there is an ASCII control code ^G after the echo. Just copy this code, and save it as ASCII/ANSI using a text editor.

use ECHO command to echo a CTRL G

I think the better solution is echoing a ^G to a file from the cmd prompt and then type that file from within the script, that way you don't need to include control characteres in the batch file itself:
C:\> echo ^G>beep.snd
Now there's an ASCII 007 char in the "beep.snd" file, then from your .bat file all you have to do is type it or copy to the screen:
type beep.snd
or
copy beep.snd con > nul

I tried all the options above in Win 10. I settled with this
powershell.exe [console]::beep(500,600)
So programmatically in node.js it would look like this (python or C would be similar)
require("child_process").exec("powershell.exe [console]::beep(500,600)");

A bit late to the party, but I find this variation on #npocmaka version works for me with Windows 10:
REM This captures the Bell as a variable.
for /f %%g in ('%__APPDIR__%forfiles.exe /p "%~dp0." /m "%~nx0" /c "cmd /c echo 0x07"') do set "bel=%%g"
REM This produces the Bell sound.
set /P "=%bel%"<NUL

This works for me..
there was a special character in line 4 which stackoverflow was omitting,
code's pasted here:
hashb.in/long
and line 5 and 6 can be used interchangeably of course.

Related

Windows CMD Start and wait for the default application in a batch file

I am trying to start the default application for a file, wait for it to complete, and then continue with my batch file. The problem is that start, when used below simply creates another command prompt window with the example.doc in the title bar. I can use call instead of start, but then call does not wait for the program to finish before going to the next line. It appears that start needs to have an executable name and will not work with the default application system in windows.
Any ideas how I can make this happen without having to hardcode the windows application in the batch file as well?
set filename=example.doc
start /wait %filename%
copy %filename% %filename%.bak
How do I start the default application for a file, wait for completion, then continue?
It appears that start needs to have an executable name and will not work with the default application system in windows.
start, when used below simply creates another command prompt window with the example.doc in the title bar
start /wait %filename%
The above command won't work because %filename% is used as the window title instead of a command to run.
Always include a TITLE this can be a simple string like "My Script" or just a pair of empty quotes ""
According to the Microsoft documentation, the title is optional, but depending on the other options chosen you can have problems if it is omitted.
Source start
Try the following command instead:
start "" /wait %filename%
Alternative solution using the default open command
Any ideas how I can make this happen without having to hardcode the
windows application in the batch file as well?
One way is to use assoc and ftype to get the default open command used for the file then execute that command.
The following batch file does that for you (so no hard coding of windows applications is needed).
Open.cmd:
#echo off
setlocal enabledelayedexpansion
set _file=example.doc
rem get the extension
for %%a in (%_file%) do (
set _ext=%%~xa
)
rem get the filetype associated with the extension
for /f "usebackq tokens=2 delims==" %%b in (`assoc %_ext%`) do (
set _assoc=%%b
)
rem get the open command used for files of type filetype
for /f "usebackq tokens=2 delims==" %%c in (`ftype %_assoc%`) do (
set _command=%%c
rem replace %1 in the open command with the filename
set _command=!_command:%%1=%_file%!
)
rem run the command and wait for it to finish.
start "" /wait %_command%
copy %_file% %_file%.bak 1>nul
endlocal
Further Reading
An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
assoc - Display or change the association between a file extension and a fileType
enabledelayedexpansion - Delayed Expansion will cause variables to be expanded at execution time rather than at parse time.
for - Conditionally perform a command several times.
for /f - Loop command against the results of another command.
ftype - Display or change the link between a FileType and an executable program.
start - Start a program, command or batch script (opens in a new window).
variable edit/replace - Edit and replace the characters assigned to a string variable.
Simply use the filename directly as command, unless that filename is a batch file, in which case use call.
In a batch file invocation of a GUI subsystem executable is blocking, unlike for an interactive command.
Use the start command when you don't want blocking execution.
There is a subtle point about “default application”, namely that a file type can have a registered default application for the graphical shell, e.g. its “Open with…”, without having an assoc/ftype association, or different from that association.
I'm not entirely sure of which registry entries are used for this. I've always had to look it up and research it each time. As I recall it's not well-documented.
But hopefully you're OK with just the assoc/ftype scheme.
A further subtle point about “default application”: on the laptop I'm writing this on the ftype association for text files is to open them in Notepad:
[H:\forums\so]
> assoc .txt
.txt=txtfile
[H:\forums\so]
> ftype txtfile
txtfile=%SystemRoot%\system32\NOTEPAD.EXE %1
[H:\forums\so]
> _
And this is what the graphical shell (Windows Explorer) will do.
But cmd.exe looks inside files, and if it finds an executable signature then it tries to run the text file as an executable, even in Windows 10:
[H:\forums\so]
> echo MZ bah! >oops.txt
[H:\forums\so]
> oops.txt
This version of H:\forums\so\oops.txt is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher.
[H:\forums\so]
> _

Running batch file with /d option

I've been working for some time on the installer for my application (using Installshield), and some time ago I came upon the problem, when batch file, that I called using LaunchApplication failed to execute (to be specific - it executed, but in the wrong directory). I decided to dig this issue up and stumbled upon this article. The problem, it turns out, lies within Autorun registry key, which is defined in following matter:
cd /d C:\Blahblah\Yadayada
So, before the batch file was actually executed, this command changed directory.
The batch file is most basic one, something like this:
:start
foo.exe %1 --bar %2 --baz %3
if errorlevel 1 goto fail
ECHO Success
goto end
fail:
ECHO Fail
:end
So, basically this batch file expects that it will be launched from the correct directory, and it's not. I'm append INSTALDIR variable to the batchname in LaunchApplication call, just to be clear, and it works perfectly fine when Autorun key is not set up.
And, well, I finally got to the question - is there any way to provide launch options for individual batch file? I know that providing /d option will render Autorun useless, but it only works only on direct call.
For instance, let's assume that I have batch file with simple 'dir' command (let's call it foo.bat), and my Autorun key is defined as shown above. I run command-prompt with /d option (CMD /d), and then run 'dir' directly I'll get content of the folder I'm currently in (e.g. user folder); BUT, if I launch foo.bat, I'll get contents of C:\Blahblah\Yadayada, because Autorun command will execute first, set default folder, and only after that 'dir' command will be called.
So, personally I see a few options here. First - removing Autorun key, and that would be the most fitting and easiest solution if it had to be applied only for one machine - I can't possibly expect every user to take care of their Autorun key for themselves. Second, which should be applicable for everyone (but which I hadn't tested yet), would be providing path to installation folder as extra parameter to batch file, and then changing directory to that:
:start
%4
cd %5
foo.exe %1 --bar %2 --baz %3
...
Where %4 would be a disk letter and %5 would be a path. This seems to be a solution, but I find it counterproductive that I have to implicitly change path to the folder, given that it works perfectly well when Autorun key is absent.
So, I was wondering if there's any workaround about this Autorun key problem. Maybe, like I've mentioned in the title, kind of /d option for batch file so that when it runs it will override global option from Autorun and will actually launch from the place it's supposed to launch, or some kind of technique like that? Also, maybe there's some kind of option in LaunchApplication() function I'm not aware of?

Pausing a batch file when double-clicked but not when run from a console window?

Is there a way for a batch file (in this case, running on Windows XP) to determine whether it was launched from a command line (i.e. inside a console window) or launched via the shell (e.g. by double-clicking)?
I have a script which I'd like to have pause at certain points when run via the shell, but not when run at a command line. I've seen a similar question on SO, but am unable to use the same solution for two reasons: first, whether or not it pauses needs to be dependent on multiple factors, only one of which is whether it was double-clicked. Second, I'll be distributing this script to others on my team and I can't realistically ask all of them to make registry changes which will affect all scripts.
Is this possible?
Found one :-) – After desperately thinking of what cmd might do when run interactively but not when launching a batch file directly ... I finally found one.
The pseudo-variable %cmdcmdline% contains the command line that was used to launch cmd. In case cmd was started normally this contains something akin to the following:
"C:\Windows\System32\cmd.exe"
However, when launching a batch file it looks like this:
cmd /c ""C:\Users\Me\test.cmd" "
Small demo:
#echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1
if defined DOUBLECLICKED pause
This way of checking might not be the most robust, though, but /c should only be present as an argument if a batch file was launched directly.
Tested here on Windows 7 x64. It may or may not work, break, do something weird, eat children (might be a good thing) or bite you in the nose.
A consolidated answer, derived from much of the information found on this page (and some other stack overflow pages with similar questions). This one does not rely on detecting /c, but actually checks for the name of the script in the command line. As a result this solution will not pause if you double-clicked on another batch and then called this one; you had to double-click on this particular batch file.
:pauseIfDoubleClicked
setlocal enabledelayedexpansion
set testl=%cmdcmdline:"=%
set testr=!testl:%~nx0=!
if not "%testl%" == "%testr%" pause
The variable "testl" gets the full line of the cmd processor call, stripping out all of the pesky double quotes.
The variable "testr" takes "testl" and further strips outs the name of the current batch file name if present (which it will be if the batch file was invoked with a double-click).
The if statement sees if "testl" and "testr" are different. If yes, batch was double-clicked, so pause; if no, batch was typed in on command line (or called from another batch file), go on.
Edit: The same can be done in a single line:
echo %cmdcmdline% | findstr /i /c:"%~nx0" && set standalone=1
In plain English, this
pipes the value of %cmdcmdline% to findstr, which then searches for the current script name
%0 contains the current script name, of course only if shift has not been called beforehand
%~nx0 extracts file name and extension from %0
>NUL 2>&1 mutes findstr by redirecting any output to NUL
findstr sets a non-zero errorlevel if it can't find the substring in question
&& only executes if the preceding command returned without error
as a consequence, standalone will not be defined if the script was started from the command line
Later in the script we can do:
if defined standalone pause
One approach might be to create an autoexec.nt file in the root of c:\ that looks something like:
#set nested=%nested%Z
In your batch file, check if %nested% is "Z" - if it is "Z" then you've been double-clicked, so pause. If it's not "Z" - its going to be "ZZ" or "ZZZ" etc as CMD inherits the environment block of the parent process.
-Oisin
A little more information...
I start with a batch-file (test.cmd) that contains:
#echo %cmdcmdline%
If I double-click the "test.cmd" batch-file from within Windows Explorer, the display of echo %cmdcmdline% is:
cmd /c ""D:\Path\test.cmd" "
When executing the "test.cmd" batch-file from within a Command Prompt window, the display of
echo %cmdcmdline% depends on how the command window was started...
If I start "cmd.exe" by clicking the "Start-Orb" and "Command Prompt" or if I click "Start-Orb" and execute "cmd.exe" from the search/run box. Then I execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:
"C:\Windows\system32\cmd.exe"
Also, for me, if I click "Command Prompt" from the desktop shortcut, then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is also:
"C:\Windows\system32\cmd.exe"
But, if I "Right-Click" inside a Windows Explorer window and select "Open Command Prompt Here", then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:
"C:\Windows\System32\cmd.exe" /k ver
So, just be careful, if you start "cmd.exe" from a shortcut that contains a "/c" in the "Target" field (unlikely), then the test in the previous example will fail to test this case properly.

Windows batch choice command for Windows XP & 2003

Is there a way to prompt users for input (ie: Yes/No) from a Windows batch script that works on XP and Windows 2003 server? It seems some commands (ie: choice) only work on one OS and not others.
Use the SET command with the /P switch.
SET /P RESULT=Y or N?
ECHO %RESULT%
Note that the SET /P command does not support all the same features as the CHOICE command. Namely:
It doesn't restrict the user to entering a valid value
The user has to press enter
You have to check for casing differences (e.g. "A" vs "a")
There is no way to default to a certain choice after a certain amount of time
For these reasons, I still prefer to use the CHOICE command rather than the SET /P command. To do this, you just need to include CHOICE.COM along with your batch file. You can download CHOICE.COM from Microsoft via the MS-DOS 6.22 Supplemental Disk. Here's the link:
http://support.microsoft.com/kb/117600
This will basically mimic what choice does, you will need to put it as a subroutine in your batch file. I also prefer choice but I need something portable that will run on Windows XP.
You can then modify this to accept other "choices," however this will work as case insensitive and repeat the prompt until the user explicitly enters Y, y, N, or n.
:yesorno
set /p choice=%2
if /i NOT %choice% == n (
if /i NOT %choice% == y goto yesorno
)
set "%~1=%choice%"
goto :eof
You would then call this subroutine via:
call :yesorno answer "Do you want to continue? [Y/n]: "
It's been working very well for me so far.
For instance you could use this:
SET /P ANSWER=y OR n?
If "%answer%"=="y" goto yes
If "%answer%"=="n" goto no
Enjoy!
Windows Millenium's CHOICE.COM works fine for me under XP SP3.
However, mine is hungarian language, but you can probably find its original english variant, for example searching for "windows millenium ebd".
http://s000.tinyupload.com/index.php?file_id=57468192666746678653

Why does batch file FOR fail when iterating over command output?

I have a batch file that uses this idiom (many times) to read a registry value into an environment variable:
FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKLM\SOFTWARE\Path\To\Key" /v ValueName') DO SET MyVariable=%%B
(There's a tab character after delims=)
This works fine on thousands of customer's computers. But on one customer's computer (running Windows Server 2003, command extensions enabled),
it fails with 'REG QUERY "HKLM\SOFTWARE\Path\To\Key" /v ValueName' is not recognized as an internal or external command, operable program or batch file.' Running the "reg query" command alone works fine. Reg.exe is present in C:\Windows\System32.
I was able to work around the problem by changing the code to
REG QUERY "HKLM\SOFTWARE\Path\To\Key" /v ValueName > temp.txt
FOR /F "tokens=2* delims= " %%A IN (temp.txt) DO SET MyVariable=%%B
This got the customer up and running, but I would like to understand why the problem occurred so I can avoid it in the future.
Slightly off the primary topic - a more direct way to get a registry value (string or DWORD) into an environment variable would also be useful.
I would check:
The customer's role on the machine - are they an admin?
Where is reg.exe on the box - is there more than one copy of copy of reg.exe in the path?
Is there any locale difference on the customer's machine from the machines where this normally works?
Basically, enumerate everything that differs between this machine and machines where it works as expected. Include service packs, domain membership, etc.
Wow, that is odd.
If the same commands work when split into two lines, then I'd guess it has something to do with the way the command gets run in a subshell in the FOR command.
If you were really dying to figure out why it's dying in this particular case, you could run commands like "SET > envvars.txt" as the FOR command and compare that with the top shell.
Or maybe start off simple and try running the REG command via CMD /C to see if that does anything?
One quick guess here, what's the values of COMSPEC and SHELL ?
I had a similar situation to this. In my case it was a bad value in COMSPEC. I fixed that and the script started working as expected.
The /F switch needs command extensions to be turned on. Usually they are turned on by default, but I'd check that. On XP systems you can turn them on doing something like
cmd /e:on
or checking the registry under
HKCU\Software\Microsoft\Command Processor\EnableExtensions
Dunno about Windows Server.
Doing help for and help cmd could provide some hints as well.

Resources