WMIC Command Not Working in For Loop of Batch File - for-loop

I have a batch file that I am trying to run, but I keep getting an error. I think that this question is similar to I can't get the right syntax to use WMIC in batch file, but dbenham's answer doesn't completely work in my case because I am piping to findstr. Here is a part of the batch file (the part it is hanging on):
for /F %%I in ('wmic nic where 'Manufacturer!="Microsoft" and Macaddress IS NOT NULL' get index ^| findstr /r [0-9]') do (
echo %%I
)
The wmic command works just fine if you run it from cmd or it's own line of a batch file, but I cannot get it to run in the for loop. Can anyone help me out here?
Thanks,
John

Try it this way:
for /f "tokens=2 delims==" %%I in (
'wmic nic where "manufacturer!=\"Microsoft\" and macaddress is not null" get macaddress /format:list 2^>NUL'
) do echo %%I
You have to backslash-escape your quoted stuff where your quotes are nested.

There is a feature in WMIC that it sometimes waits for user input.
If you replace
wmic
in your example, with
echo. ^| wmic
it will allow the command to complete

Related

Combining two batch files / "do"ing more than one command per "do"

Essentially what I want is to get the the user that's currently using a computer. I got the below code from this community which works well...,
::Batch 1
#echo off
for /f %%a in (output1.txt) do WMIC /NODE:%%a computersystem GET name, username
do echo %%r >> output2.txt
..., except that my computer names have hyphens in them and cannot be used.
To circumvent that, I run the below code (also got this here, thanks again!) to retrieve the IPs first:
::Batch 2
#echo off
for /f %%a in (hosts.txt) do call :process %%a
goto :eof
:process
set hostname=%1
for /f "tokens=4 delims=: " %%r in ('ping -n 1 %hostname%^|find /i "Statistics"') do echo %%r >> output2.txt
I then feed this information to the first batch file above to get the hostnames.
So essentially I place my hostnames on a txt file named Hosts.txt, run batch 2, then run batch 1.
I've tried many days to combine the both, but cant seem to figure it out.
As #aschipfl suggested. Use FOR /? to see information about using the FOR command.
for /f %%a in (output1.txt) do (
WMIC /NODE:%%a computersystem GET name, username
ECHO right here
)

Quoting a long filenamed command in a for loop in a batch file

Linked:
Best free resource for learning advanced batch-file usage?
Dealing with quotes in Windows batch scripts
This appears to be one of those maddening quoting issues. In this example program:
#echo off
set wmicpath=%windir%\System32\wbem\wmic.exe
for /f "usebackq" %%a in (`%wmicpath% COMPUTERSYSTEM GET SystemType ^| findstr /I "x64"`) do (
echo %%a
)
The program runs just fine. Unless you try to quote the wmicpath. Imagine if you will that it contains a long path name. Then you should quote it. But I cannot quite get it to work. This fails:
for /f "usebackq" %%a in (`"%wmicpath%" COMPUTERSYSTEM GET SystemType ^| findstr /I "x64"`) do (
but this works!:
for /f "usebackq" %%a in (`"%wmicpath%" COMPUTERSYSTEM GET SystemType ^| findstr /I x64`) do (
as does this:
for /f "usebackq" %%a in (`"%wmicpath%" COMPUTERSYSTEM GET SystemType`) do (
There's something really odd about matching quotes in a for command. You can quote a command as long as you don't start quoting elsewhere...
Is it possible? I tried escaping at various points but I'm not sure about the escaping rules when quotes are involved...
Edit: I think this link might be the issue (ie: it's a bug): Pipe in for loop breaks double quoted variables
#echo off
setlocal enableextensions disabledelayedexpansion
set "wmicpath=%windir%\System32\wbem\wmic.exe"
for /f "usebackq delims=" %%a in (`
^""%wmicpath%" COMPUTERSYSTEM GET SystemType ^| findstr /I "x64"^"
`) do (
echo %%a
)
If you look at the start and end of the inner command, you will see two additional ^" (a escaped double quote). Your problem is that the for command is spawning a separate instance of cmd to handle the inner command, and this separate instance is removing the initial and final double quotes.
Why escaped quotes? To avoid this additional quotes being paired with the double quotes in the command that could lead to some other parsing problems.
You can run cmd /? to obtain the help page (sorry, i have a spanish locale so i will not include the output here). You will see a section about the /C and /K usage explaining quote removal behaviour.
First of all I would change the command, WMIC allows you to use a query language LIKE operator which would in this case remove the need to pipe anything.
#Echo Off
Set "WMIC=%SystemRoot%\System32\Wbem\wmic.exe"
For /F "UseBackQ Skip=1" %%a In (
`""%WMIC%" ComputerSystem Where "SystemType Like 'x64%%'" Get SystemType"`
) Do For %%b In (%%a) Do Echo=%%b
Timeout -1
Then I may even change the format of the command such that I don't use back quotes.
#Echo Off
Set "WMIC=%SystemRoot%\System32\Wbem\wmic.exe"
For /F "Skip=1" %%a In (
'""%WMIC%" ComputerSystem Where (SystemType Like "x64%%") Get SystemType"'
) Do For %%b In (%%a) Do Echo=%%b
Timeout -1
Whilst this doesn't directly answer the question in the subject title, it does allow for your particular command to work correctly.
However neither are necessary to your particular command example, because you do not need the for loop to echo that output:
#Echo Off
Set "WMIC=%SystemRoot%\System32\Wbem\wmic.exe"
"%WMIC%" ComputerSystem Get SystemType|Find /I "x64"
Timeout -1
Change Find to FindStr if you feel the need.
>x64.txt ECHO x64
for /f "usebackq" %%a in (`"%wmicpath%" COMPUTERSYSTEM GET SystemType ^| findstr /I /g:x64.txt`) do (
might be a work-around, depending on your actual application and preferences.

Detecting Removable drive letter in CMD

I'm trying to write a script, which will detect the letter of my USB Removable Drive called "UUI" and then create folder on it. I've written few commands for CMD which, when run separately, work. However when I put them into a bat file, I always get some errors. Here are the commands in a bat file:
for /F "tokens=1 delims= " %i in ('WMIC logicaldisk where "DriveType=2" list brief ^| c:\windows\system32\find.exe "UUI"') do (echo %i > drive.txt)
set /p RemovableDriveLetter2= < drive.txt
del /F /Q drive.txt
set RemovableDriveLetter=%RemovableDriveLetter2:~0,1%
%RemovableDriveLetter%:
md MyNewFolder
cd MyNewFolder
When I go to cmd.exe and run the file by calling "myScript.bat" or "call myScript.bat", I get an error:
C:\Users\UUI\Desktop>myScript.bat
\windows\system32\find.exe was unexpected at this time.
C:\Users\UUI\Desktop>for /F "tokens=1 delims= " \windows\system32\find.exe "UUI"') do (echo i > drive.txt)
C:\Users\UUI\Desktop>
I can see that MyNewFolder was not created. However, when I copy all lines and run them in CMD as such (e.g. not in the .bat file) and run them one by one, it is fully functional within the cmd.exe instance.
How can I create bat a file, which will successfully run and detects the drive letter of my removable drive without issues? Or how can I solve the error "\windows\system32\find.exe was unexpected at this time."?
You need to double the % sign used to mark a FOR loop control variable in a batch script (.bat or .cmd), i.e. use %%i instead of %i used in pure CLI.
However, there is another possible approach how-to parse wmic output.
See also Dave Benham's WMIC and FOR /F: A fix for the trailing <CR> problem
#echo OFF
SETLOCAL enableextensions
set "USBCounter=0"
for /F "tokens=2 delims==" %%G in ('
WMIC logicaldisk where "DriveType=2" get DeviceID /value 2^>NUL ^| find "="
') do for /F "tokens=*" %%i in ("%%G") do (
set /A "USBCounter+=1"
echo %%i
rem your stuff here
)
echo USBCounter=%USBCounter%
rem more your stuff here
ENDLOCAL
goto :eof
Here the for loops are
%%G to retrieve the DeviceID value;
%%i to remove the ending carriage return in the value returned: wmic behaviour: each output line ends with 0x0D0D0A (CR+CR+LF) instead of common 0x0D0A (CR+LF).
One could use Caption or Name instead of DeviceID:
==>WMIC logicaldisk where "DriveType=2" get /value | find ":"
Caption=F:
DeviceID=F:
Name=F:
Note there could be no or more disks present having DriveType=2:
==>WMIC logicaldisk where "DriveType=2" get /value | find ":"
No Instance(s) Available.
==>WMIC logicaldisk where "DriveType=2" list brief
DeviceID DriveType FreeSpace ProviderName Size VolumeName
F: 2 2625454080 3918512128 HOMER
G: 2 999600128 1029734400 LOEWE
Script output for no, then one and then two USB drive(s), respectively:
==>D:\bat\SO\31356732.bat
USBCounter=0
==>D:\bat\SO\31356732.bat
F:
USBCounter=1
==>D:\bat\SO\31356732.bat
F:
G:
USBCounter=2
==>

I need a windows command line script that takes an output, edits it and creates an environmental variable

I have Asset tags embedded in BIOS. I use
wmic SYSTEMENCLOSURE get SMBiosAssetTag
This pulls the information I want but it is not formatted well:
SMBIOSAssetTag
11886
I need to just have those 5 numbers and nothing else. I will then use that variable to name the computer with a first logon script. I have spent hours on this, and I could have been done in 3 minutes if this was linux.
Note: I can't put linux tools on these builds :-(
Using
WMIC SYSTEMENCLOSURE GET SMBiosAssetTag /FORMAT:VALUE
will make a better output:
(some empty lines)
SMBIOSAssetTag=CZC1296FLD
(some empty lines)
So, in batch you may just
FOR /F "TOKENS=1,* DELIMS==" %%v IN (WMIC SYSTEMENCLOSURE GET SMBiosAssetTag /FORMAT:VALUE) DO IF /I "%%v" == "SMBIOSAssetTag" SET SMBIOSAssetTag=%%w
Side note: hard part in WMIC output is handling empty lines.
This will work, tested it myself:
for /f "eol=S" %%a in ('wmic SYSTEMENCLOSURE get SMBiosAssetTag^|sort') do (set var=%%a)
It works fine.
Mona
for /f "delims=" %%a in ('wmic SYSTEMENCLOSURE get SMBiosAssetTag') do for /f %%b in ("%%a") do set "var=%%b"
echo %var%

'cut' like feature for Windows batch file

It's been a while since I've done Windows batch files, and I seem to have forgotten everything. What I want to do is look for services where the path has spaces but the string isn't quoted. Boy, this would be easy with bash, but...
So, in a nutshell, I start with sc query | findstr SERVICE_NAME and dump that to a temp file. Then I read it back in to a variable with for /F "tokens=2" %%f in (temp_file) do set services=!services! %%f That gets me a variable with a space-delimited list of all services on my host. Now, in a FOR loop against that variable, I run sc qc %%s | findstr BINARY_PATH_NAME and dump THAT to a temp file. It winds up containing something like (quotes are mine to preserve all the spaces):
" BINARY_PATH_NAME : C:\Windows\system32\svchost.exe -k LocalSystemNetworkRestricted"
I've been reading and Googling and testing and trying everything, trying to wind up cutting that output at the : so I can just wind up with the path itself, and then start figuring out the abomination that must be regular expressions under Windows. But I just cannot get that string split.
You can do the following if you want the binary path for all services:
for /f "tokens=2" %%n in ('sc query ^| findstr SERVICE_NAME') do (
for /f "delims=: tokens=1*" %%r in (
'sc qc "%%~n" ^| findstr BINARY_PATH_NAME'
) do (
echo %%~s
)
)
Change echo %%~s to echo %%~n:%%~s if you want the binary path prepended with the name of the service.
Ansgar Wiechers has a good solution using SC to get the info for running services. It also demonstrates how to use the FOR /F delims option to break at the :.
Another option is to use WMIC to get the same information in a more direct manner.
If all you want is a list of binary paths for all active (running) services, then all you need is:
wmic service where "state='Running'" get pathname
If you want the list of service names as well as the binary paths:
wmic service where "state='Running'" get name, pathname
There are many more properties that can be listed. Type wmic service get /? from the command prompt to get a complete list.
If you want to get the values into variables within a batch process so that you can take action, then a FOR /F loop is used. I append the state property at the end to avoid an odd FOR /F quirk that appends an unwanted <CR> to the end of each line of WMIC output. The unwanted <CR> will be attached to the state value, which we don't care about. I also use the state with FINDSTR to weed out unwanted lines, so there is no need for the WMIC WHERE clause. In this example I simply echo the values, but obviously you could do whatever is needed with them.
for /f "tokens=2,3 delims=," %%A in (
'"wmic service get name, pathname, state /format:csv|findstr /e Running"'
) do echo %%A: %%B
Something like this?
#echo off
for /f "tokens=2 delims=: " %%a in ('sc query ^| findstr SERVICE_NAME') do (
sc qc %%a | findstr BINARY_PATH_NAME
)
pause

Resources