Command Line FOR /F Fails - batch-file

I have a DOS build script which works on one Windows Server 2008 R2 but not another. To see the symptoms on the broken machine entering either of the following at the command line:
for /f %X in ('dir /b *.txt') do #echo %X
for /f "usebackq" %X in (`dir /b *.txt`) do #echo %X
gives: "'dir /b *.txt' is not recognised as an internal or external command." while e.g.
for %X in (*.txt) do #echo %X
works fine, so the /f is not being obeyed properly. I don't believe this is the Command Extensions themselves (starting cmd /x shows the same behaviour; running them inside cmd /y on the problem server gives the normal "/f was unexpected at this time"). I have also checked the command extensions registry keys and tried "setlocal enableextensions" in the batch files.
I don't think it's relevant but differences between the servers are that the failing one is physical; its CPU doesn't have VT extensions; does have McAfee installed. As far as I know they were installed the same way though at different times.
Does anyone have any suggestions? I am stuck!

Check the COMSPEC environment variable in on the machine where it doesn't work, i.e. do echo %COMSPEC% and see what it contains (it should be %windir%\system32\cmd.exe or comparable).
Long Story:
You're detailed question ruled out all other potential possibilities (like the need to use %%X instead of %X inside batch files, as compared to the command line), like fiddling with setlocal enableextensions (or comparable switches, registry entries, etc.). And by the way, the error message would not fit.
If you get the error message "...is not recognised as an internal or external command" it is, that CMD.EXE cannot find the command you're trying to execute. Since "dir" is an internal command "this should never happen", of course.
I was able to reproduce your error doing the following:
Start CMD.EXE
Enter the following SET ComSpec=DoesNotExist
Enter the following CMD.EXE, i.e. start another, nested, CMD.EXE session. This step is required, in a running CMD.EXE session, the change to ComSpec seems to go unnoticed.
In the new CMD.EXE session enter your command (e.g. for /F %x in ('dir /b') do #echo%x), you should get the error you see. Note if you just enter dir it will still work, so you have to have that "indirect" execution via, e.g., a for loop. Funny.
Note that this was all done to reproduce what you are seeing, the reasons exact environmental or setup conditions that lead to this behavior on your system might be different, however the fact that the ComSpec environment variable refers to something other than CMD.EXE should be the same.

In a batch file you have to use double-percents i.e. %%X.
At the command line single percents are fine.
As to why it works on one machine, not sure, perhaps its somehow being run via 16 bit DOS on the machine which works? Or it was a different test that appears to work without the variable substituion working.

Related

How to fix Windows batch file FOR command returing "Active code page: 65001"

If I understand correctly this batch script
for /f "usebackq tokens=*" %%i in (`time /t`) do (
echo "%%i"
)
echo "done"
should just print the time and then "done"
Instead though on my machine, Windows 10 Pro x64 it prints
>test.bat
>for /F "usebackq tokens=*" %i in (`time /t`) do (echo "%i" )
>(echo "Active code page: 65001" )
"Active code page: 65001"
>(echo "17:48" )
"17:48"
>echo "done"
"done"
Why is it doing this and how do I fix it so it just gets the time and not this "Active code page: 65001" result. This is breaking build scripts as it doesn't matter what command goes in the FOR command the first line is always "Active code page: 65001"
To be clear I'm looking for an OS setting fix, not a fix to the batch file. The real batch files I'm trying to run are from build scripts in open source projects and they are failing because of this issue.
When we run a command and we get the correct output, but it is preceded by the output of another command, somehow this unexpected command is run before our intended command.
The usual suspect is a batch file created with the same name that the command we are calling, but in this case, being time an internal command, this can not be the case, internal commands have precedence over external commands (default behaviour).
If time is an internal command, how can another command being called?
When for /f needs to process the output of a command a separate cmd instance is created to execute that command. The output generated in this separate instance is processed by the code in the do clause of the for /f command.
The creation of this separate instance can be the source of the unexpected output.
Reading the help information shown by cmd /? we can see that there are two registry keys
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun
HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun
that can be configured to run commands every time a new cmd instance is created (unless the /D switch is used when starting the cmd instance).
This is the most probable place where to find why you get the Active code page: 65001 output.
Instead of changing the registry you can control the code page simply by creating a file %HOMEPATH%\init.cmd.
Mine says:
#ECHO OFF
CHCP 65001 > nul
You need to suppress the output from CHCP to avoid the undesired output.

Trying to place a file in a remote destination

I'm attempting to replace an old executable on a system that's currently running the program with a new copy of said program. I've been able to make some headway but it seems I've twisted myself up a bit and am now getting errors. Here's what I'm trying to do:
1) Prompt technician for the IP address (this works)
2) Kill the program actively running on the target system (this works)
3) Copy the new executable from the "current directory" to the appropriate place on the target system. (Sideways)
I've attempted many iterations of this but I cannot seem to find a combination that works using either copy or xcopy (attempted the same code using both).
set /p ROOT="Enter Machine IP Address: "
taskkill /S %ROOT% /IM mobileRecorder.exe /F
taskkill /S %ROOT% /IM mobileMenu.exe /F
set TARGET=\\%ROOT%\C$\Program Files\MobileRecorder\
xcopy mobileRecorder.exe %TARGET%
The above yields "Invalid number of parameters" error (using COPY it reads, "The syntax of the command is incorrect")
I have also attempted to combine the last two lines using:
xcopy mobileRecorder.exe \\%ROOT%\C$\Program Files\MobileRecorder\
And:
xcopy .\mobileRecorder.exe \\%ROOT%\C$\Program Files\MobileRecorder\
Any assistance would be greatly appreciated!
xcopy mobileRecorder.exe "%TARGET%"
Since target contains a space, you need to group the string to provide a single token.

Batch script fails when run as admin from explorer, but not when run as admin from terminal?

I have a batch script that needs to run as admin. I will be distributing to users so it would be best if they can run it from Windows Explorer.
Unfortunately, it doesn't work when run from explorer (right click -> run as admin). It does work when called from a pre-existing admin terminal.
Initially I thought the problem was with the active directory, but I added a "cd /d %~dp0" as the first command. I confirmed through echo that this places them both in the same directory, but it still fails when running from explorer.
The failure occurs when reading an external file in the same directory as the .bat. It pulls empty strings when run from explorer. Here is sample code:
rem Make sure active directory is correct (verified that this works)
cd /d %~dp0
rem Load parameters from params.txt
for /f "delims== tokens=1,2" %%G in ("params.txt") do set %%G=%%H
rem Print params (it's a loop so you can read it when running from expl.)
for /l %%a in (1 1 100000) do echo %DST%
Then you just need to make sure params.txt is in same directory as .bat and includes the line "DST=some\directory\name"
Anybody know why this doesn't work?
As has been pointed about by #nephi12 in his answer if your file name does not have spaces you can remove the quotes, otherwise it thinks the IN clause is a string you want to parse. If you need to quote your file names then you need to use the USEBACKQ option as pointed out by the comments. Once you use that option your code works just fine.
But I would like to make a point with your code. If the contents of your params.txt file is:
"DST=some\directory\name"
Then your FOR command can just be this:
for /f "usebackq tokens=1 delims=" %%G in ("params.txt") do set %%G
I am not understanding why you are echoing the %dst% variable 100,000 times?
For one thing, take away the "s from around params.txt as double-quotes means string parsing, while unquoted is a list of files.
Second, try prepending params.txt with %~pd0\ to ensure the correct path, rather than changing directory.

Using dash and switches in batch script

I just created simple batch script. I want to run uninstall.exe with switches like "-q" "-splash Uninstall"
Here is the code;
#echo off
echo This script will uninstall some features.
pause
SET path=C:\Program Files\Program\uninstall.exe -q -splash Uninstall
START "" "%path%"
pause
If I run this code it gives an error:
Windows cannot find 'C:\Program Files\Program\uninstall.exe -q -splash Uninstall'
Make sure you typed the name correctly, and then try again.
If I remove switches, uninstall process starts normally.
So how can I use this swtiches in a batch file?
As an aside, don't use path as an arbitrary choice of variable name. It has a special significance in Windows (and Unix-derived systems too).
Your main problem is that you are including the switches in your quoted string, which is then treated as a whole as the executable filename. Put your quotes only around the filename, and leave the switches outside:
SET command="C:\Program Files\Program\uninstall.exe" -q -splash Uninstall
START "" %command%
(The only reason for the quotes is the fact that the pathname contains spaces.)
Also, you don't really need to use a variable at all, but I've used one since you used one.
I'm not quite sure if every program you come across will have a uninstall.exe file waiting for you in the C:\Program Files(place program name here)\ directory. Even if it does, you will probably have to control it from the GUI. However, looking at another stack overflow thread here, I would like to credit the users Bali C. and PA. for coming up with a possible solution to uninstall files using a batch file by using the registry key to find an uninstall file for windows programs. I will re-paste PA.'s code below:
#echo off
for /f "tokens=*" %%a in ('reg query hklm\software\Microsoft\Windows\CurrentVersion\Uninstall\ ^| find /I "%*"') do (
for /f "tokens=1,2,*" %%b in ('reg query "%%a" /v UninstallString ^| find /I "UninstallString"') do (
if /i %%b==UninstallString (
echo %%d
)
)
)
This code will find the uninstall file for a specific program from the registry, and then it will print out the command needed to run the uninstall file. Remove the 'echo' to just run these commands when you are sure they are correct. However, even this will probably require using the program's uninstall GUI. I don't think this would be terribly inefficient. Is there any other specific reason you want to use a batch file besides efficiency?
I hope this helps!

start /w not working anymore?

I have always used start /w in batch files and from a Windows console to run something and pause till the application is closed. But since a few weeks ago, this does not work anymore!
I tried to simply open one by one the .pdf files in a folder and it doesn't work. So I studied for at least 3 hours what could be wrong to no avail. And nobody on the Internet seems to mention a problem like that. Today I picked a batch I used in the past to open files in sequence and it doesn't work anymore either. It would use two simple batches, the core one doing just this:
cd %1
for %%f in (*.py) do start /wait %%f
cd ..
I am pretty sure I used it successfully on the same machine I use now (Win7 Professional, 64-bit). I tried all sorts of things like call, command /b with the command, but none of them works.
From the console when I do ver I get Microsoft Windows [Version 6.1.7601] (from the 32 or the 64-bit console).
What do you think has gone wrong here?
In one of your comments, you show that the following specific command fails from the command line:
for %a in (*.pdf) do start /wait "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" %a
It doesn't work properly because the first argument is treated as a title if it is quoted. If you need to quote your executable, then you must precede the program with a quoted title. You can provide an empty title if you want:
for %a in (*.pdf) do start /wait "" "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" %a

Resources