batch file IF condition - if-statement

I'm trying to get the current active connection with netsh (i'd rather not use wmic) using the following code.
#echo off
FOR /F "tokens=3,*" %%A IN ('netsh interface show interface^|findstr /i "\<connected\>"') DO (
if %%B == .........
)
I only want to account for the default connection names:
Wi-Fi, Ethernet, Wireless Network Connection, Local Area Connection and do something based on that.
eg: if %%B = WiFi or Ethernet or....(
::do something here
)
I only want "something" to be executed once because only 1 of those connections will ever be active at any given time.

I think something like this ought to do the trick:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "tokens=3,*" %%a in ('netsh interface show interface ^| findstr /i "\<connected\>"') do (
set ifname=%%b
if "!ifname:~0,8!"=="Ethernet" goto execute
if "!ifname:~0,21!"=="Local Area Connection" goto execute
if "!ifname:~0,5!"=="Wi-Fi" goto execute
if "!ifname:~0,27!"=="Wireless Network Connection" goto execute
)
echo No connected interface found, exiting...
goto :EOF
:execute
echo Found connected interface (%ifname%), executing...
:: do whatever you need
Basically the idea is to look for interfaces that begin with those four different strings, then jump to the label that executes whatever it is you want.
[I'd be remiss if I didn't point out that this is likely better to be done in PowerShell nowadays, but…]

Here's an untested example, which is supposed to just tell you the interface name of the device associated with your only assigned IP Address.
#Echo Off
SetLocal EnableExtensions
For /F "Delims==" %%G In ('"(Set Interface) 2> NUL"') Do Set "%%G="
For /F Tokens^=4 %%G In ('%__APPDIR__%ROUTE.EXE -4 PRINT 0.0.0.0 ^
^| %__APPDIR__%findstr.exe /RC:"0.0.0.0 *0.0.0.0"') Do (Set "InterfaceIP=%%G"
For /F Tokens^=5* %%H In ('%__APPDIR__%netsh.exe interface IP show route^
^|%__APPDIR__%find.exe "%%G"') Do Set "InterfaceName=%%I")
If Not Defined InterfaceIP GoTo :EOF
Set Interface & Pause
[EDIT /]
Here's a slightly modified version of the example from my comments which uses ping.exe instead of ROUTE.EXE for returning the IP Address used to determine the Interface Name.
#Echo Off
SetLocal EnableExtensions
For /F "Delims==" %%G In ('"(Set Interface) 2> NUL"') Do Set "%%G="
For /F "Tokens=2 Delims=[]" %%G In ('^"%__APPDIR__%ping.exe "%COMPUTERNAME%" ^
-n 1 -4 2^> NUL ^| %__APPDIR__%find.exe /I "%COMPUTERNAME%"^"') Do (
Set "InterfaceIP=%%G" & For /F Tokens^=5* %%H In ('%__APPDIR__%netsh.exe ^
interface IP show route ^| %__APPDIR__%find.exe "%%G"'
) Do Set "InterfaceName=%%I")
If Not Defined InterfaceIP GoTo :EOF
Set Interface & Pause
The last line in both examples just displays the two variables so that you can see them. You'd obviously replace those with the rest of your code.

Related

How to create a .bat file to enable or disable a specific audio device with an if statement

With my little knowledge of writing code, I am trying to make a batch file where I can disable or enable a line in audio device with an IF statement.
For example, if the device is currently enabled, when I run the .bat file it will disable. If it's disabled, then it enables it.
I have the the device ID ("SWD\MMDEVAPI{0.0.1.00000000}.{55e90a30-8001-4bc8-af56-52998c03ed88}"). I am currently using pnputil /disable-device which works. But I don't know how to go about the IF statement. Would appreciate some help with that.
Edit: Okay so I found a tool called SoundVolumeView.exe that can lower the sound so the white noise can't be heard on startup. It can also mute as well all through command line.
I wasn't sure if you had solved this yourself already and I know I'm not supposed to spoon feed code on here but I had a script that did something similar and thought I should contribute. If you have any issues with this script, please comment with your issue.
Explaination: it runs pnputil /enum-devices /ids and looks at the output until it gets to a line with the device id. It sets a variable called ahead to 4. If ahead is above 0, then it will check if it is 0, if it isn't then it will go to the next line in the output of the command. If it is 0, then it will go to the toggle label and then it will check the line if it doesn't say Started. If it doesn't have Started in the line, then it will enable your device, if it does say started, then it will disable it. Then it just pauses and exits.
#echo off
setlocal enableDelayedExpansion
REM Needs to be run as administrator to work
set device=SWD\MMDEVAPI{0.0.1.00000000}.{55e90a30-8001-4bc8-af56-52998c03ed88}
set ahead=-1
for /f "delims=" %%a in ('pnputil /enum-devices /ids') do (
set "line=%%a"
if !ahead! GEQ 0 (
if !ahead!==0 goto :toggle
set /a ahead-=1
) else (
if not "x!line:%device%=!"=="x!line!" (
set ahead=4
)
)
)
:toggle
if "x!line:Started=!"=="x!line!" (
REM Device is not running
pnputil /enable-device "%device%" >nul
echo Enabling device...
) else (
REM Device is running
pnputil /disable-device "%device%" >nul
echo Disabling device...
)
pause
exit /b 0
For documentation on PnPUtil: https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/pnputil-command-syntax
For information on on for loops: https://ss64.com/nt/for.html, https://stackoverflow.com/a/50704943/19341457
For information on finding if a substring is in a string: https://stackoverflow.com/a/7006016/19341457
For information on delayed expansion: https://ss64.com/nt/delayedexpansion.html

Parsing KBs from systeminfo in batch

Question:
What is a method that can parse out just the hotfix KB entries in a Windows systeminfo command report.
Background:
I have many windows systems that I need to get the list of installed KBs from. I can't install any software on the systems, so I've resolved to use a batch file.
I would like to have a list of KBs as the output, saved to a file " .txt"
My Current Method:
So far, I can get the full list from systeminfo and put the entire output into a text file named with the device's host name and date and stick it in a directory called Systeminfo Saves. That works well enough for me, but I'm really only interested in the KBs and I am hoping to use that output to compare it to a list of validated KBs so I can get a list of KBs that need installed.
I've been messing around with for statements and tokens and delimiters to narrow down the list to just the KB files, but without success.
Here's my current code:
#echo off
REM Get date and host and set it to sFileName
REM -----------------------------------------
setlocal enabledelayedexpansion
set ssDate=%date%
set sHost=%computername%
set sDate=!ssDate:/=-!
REM Remove the day of the week
set sDate=%sDate:~-10%
set sFileName=%sHost% %sDate%.txt
REM -----------------------------------------
REM - Save system info to hostname and date -
REM -----------------------------------------
systeminfo > "Systeminfo Saves/%sFileName%"
REM
REM PUT FOR STATEMENT HERE FOR OUTPUT OF JUST KBs
REM -----------------------------------------
My next step that I haven't been able to pull off is to parse out the installed KBs into a file.
For statements have thrown me for a loop (pun mildly intended). I've tried this:
REM OUTPUT a list of KBs
SET count=1
set lookieloo = "]: KB"
FOR /F "tokens=* USEBACKQ" %%F IN (`systeminfo`) DO (
SET var!count!=%%F
SET /a count=!count!+1
REM See if "]: KB" is in the resultant string
if not x%%F:"]: KB"=%==x%%F echo %%F >> "Systeminfo Saves/%sFileName%"
)
I'm splicing together answers that I don't fully understand from other Stack Overflow answers that partially answer my question.
The last save to file I'm fairly sure won't work
.
The "]: KB" doesn't work at all. I tried using the variable lookieloo to get that statement to work. I didn't get an error, but I didn't get a list of KBs either.
So, the question is: What would a batch program look like to export a text file of installed KBs on a system using the systeminfo command?
From LotPings comment, I was able to put together a full program that extracts the installed KBs using just batch.
#setlocal enableextensions enabledelayedexpansion
#echo off
REM Get date and host and set it to sFileName
REM -----------------------------------------
set ssDate=%date%
set sHost=%computername%
REM Get the directory and make it if it doesn't exist
set sDir=Systeminfo Saves
if not exist "%sDir%\" mkdir "%sDir%\"
set sDate=!ssDate:/=-!
REM Remove the day of the week
set sDate=%sDate:~-10%
REM Compile the full file name with directory
set sFileName=%sDir%^\%sHost% %sDate%.txt
REM -----------------------------------------
echo %sFileName%
REM -- Extract KB information and save to file --
(For /f "tokens=2delims=: " %%A in ('systeminfo^|findstr "\[[0-9][0-9]*\]:.KB[0-
9]*"') Do #Echo:%%A)>"%sFileName%"
REM ---------------------------------------------
Loading and parsing SystemInfo is a time consuming operation and whilst determining the updates can take a while on its own, using WMI is probably a quicker method.
Here's an alternative which uses WMIC:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "sDir=WMIC Saves"
Set "sDate=%DATE:/=-%"
Set "sDate=%sDate:~-10%"
Set "sFileName=%sDir%\%COMPUTERNAME% %sDate%.txt"
If Not Exist "%sDir%\" MD "%sDir%" 2>Nul || Exit /B
(For /F "EOL=H Tokens=*" %%A In ('"WMIC QFE Get HotFixID|Sort"'
) Do For /F "Tokens=*" %%B In ("%%A") Do Echo=%%B)>"%sFileName%"

Using batch to read a certain section of a file and create a variable

I've read a lot of things and I can't find away of doing this that I understand. This might be because I'm a wee newbie though.
What I'm trying to do is:
I have a file called start.txt with the contents
..\dll | toapp.exe "..\posdata\filename.xml" "..\OUT" "..\TEMP"
I want to read the contents of that in a batchfile and take only filename.xml as a variable. From device to device inside the network it changes.
I'm then going to use that variable to copy a file from 1 machine to another but I only want that one file and I can't be sure what it's called without looking in the start.txt. I can do all the copy and checks to make sure it's looking in the correct places but just not the findstr section.
Any idea of what to do to understand would be fantastic
#echo off
set "start_file=start.txt"
for /f tokens^=5^ delims^=\^" %%# in ('type "%start_file%"^|find /i "..\posdata"') do set "xml_file=%%#"
echo %xml_file%
Your question is a little bit unclear.Is this the only line in the file? Is this the exact content? How can I recognize the line with the file?
The script above will work in case there's only one line wwith "..\postdata" string and the content is exact as described in question.
Edit Covering the both cases:
#echo off
setlocal
set "start_file=start.txt"
set "xml_file="
for /f tokens^=5^ delims^=\^" %%# in ('type "%start_file%"^|find /i "..\posdata"^|find /i /v "-storedbpath"') do set "xml_file=%%#"
if not defined xml_file (
for /f "usebackq tokens=9" %%# in ("%start_file%") do (
set "xml_file=%%~#"
)
)
echo %xml_file%
Text this:
for /f "usebackq tokens=4" %%a in ("start.txt") do echo %%~nxa

Multiple instances of a RegEx string in FINDSTR

I am looking for a way in a Windows batch file to find if a file contains the word Shutdown a given number of times.
I have tried this using FINDSTR:
FINDSTR /r .*Shutdown.*{5} file.txt
This doesn't seem to work, but if I remove the {5} it executes successfully.
Also I would eventually like the 5 to be a variable, presumably this is possible with some sort of dynamic command?
Thanks
It is possible to use FINDSTR to detect if "Shutdown" appears 5 or more times anywhere within a file. All the information you need is contained within What are the undocumented features and limitations of the Windows FINDSTR command?, but it is more than a bit tricky and not at all obvious.
A regex search can match multiple instances of Shutdown across multiple lines, as long as all intervening characters, including carriage return and linefeed characters, are matched by an appropriate character class range. I cannot post the characters required here, so I will use symbolic notation within angle brackets.
The following regex expression will match any byte character except 0xFF (decimal 255). It consists of a character class expression with two ranges and a gap in the middle for 0xFF. The gap is critical because FINDSTR will fail (and possibly hang) if 0xFF is included:
[<0x01>-<space><tab>-<0xEA>]
You might think the expression should be [<0x01>-<0xFE>], but that does not work because FINDSTR does not collate characters by the numeric code value.
So to look for 5 or more instances of Shutdown anywhere within the file, you would need the following regex search:
Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown
The 0xEA (decimal 234) character is an extended ASCII character, and extended ASCII cannot be included on the command line of a FINDSTR search. So the search string must be put in an external file and the /G:file option must be used.
Here is a complete batch script that takes the minimum number of Shutdown instances to search for as the 1st argument, and the name of the file to search as the 2nd argument. Again I use symbolic notation within angle brackets in place of the actual characters needed.
#echo off
set count=%1
set file=%2
setlocal enableDelayedExpansion
set "search="
for /l %%N in (1 1 %count%) do set "search=!search!Shutdown[<0x01>-<space><tab>-<0xEA>]*"
set "search=!search:~0,-9!"
echo(!search!>search.txt
findstr /rg:search.txt %file% >nul&&echo FOUND||echo NOT found
The maximum supported count is limited by the maximum regex string length. For XP the max regex length is 127 bytes, equating to a count of 7. On Vista and Windows 7 the max regex length is 254 bytes, which should support a count of 15. But my testing on Windows 7 only supported a count up to 12. Additional tests reveal the max length is affected by how many string literals and character classes appear, as well as the relative placement of each. But I haven't been able to figure out an exact formula.
If you don't want to use an external file, then the following regex expression is almost as good. It matches any characters except for the following extended ASCII hex codes: 0xE0, 0xE2, 0xE3, 0xE4, 0xE5, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xED, 0xEE, 0xFF.
[<0x01>-<space><tab>-Z]
The full regex search would be:
Shutdown[<0x01>-<space><tab>-Z]*Shutdown[<0x01>-<space><tab>-Z]*Shutdown[<0x01>-<space><tab>-Z]*Shutdown[<0x01>-<space><tab>-Z]*Shutdown
And here is the complete batch script:
#echo off
setlocal enableDelayedExpansion
set count=%1
set file=%2
set "search="
for /l %%N in (1 1 %count%) do set "search=!search!Shutdown[<0x01>-<space><tab>-Z]*"
set "search=!search:~0,-9!"
findstr /rc:"!search!" %file% >nul&&echo FOUND||echo NOT found
.*Shutdown.*Shutdown.*Shutdown.*Shutdown.*Shutdown.*
would seem to be the only way for FINDSTR
srsly.
Test batch:
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%i IN (f5shutdown.txt) DO (
ECHO %%i|FINDSTR /r .*Shutdown.*Shutdown.*Shutdown.*Shutdown.*Shutdown.* >NUL
IF ERRORLEVEL 1 ECHO FAILED IN "%%i"
IF NOT ERRORLEVEL 1 ECHO FOUND IN "%%i"
)
GOTO :eof
Test textfile in f5shutdown.txt
Shutdown
Shutdown Shutdown
Shutdown Shutdown Shutdown Shutdown
Shutdown Shutdown Shutdown Shutdown Shutdown
Shutdown already !Shutdown Shutdown Shutdown Shutdown now
You should now Shutdown Shutdown Shutdown Shutdown Shutdown
ShutdownShutdownShutdownShutdownShutdown
OK, don't shutdown then...
Result:
FAILED IN "Shutdown"
FAILED IN "Shutdown Shutdown"
FAILED IN "Shutdown Shutdown Shutdown Shutdown"
FOUND IN "Shutdown Shutdown Shutdown Shutdown Shutdown"
FOUND IN "Shutdown already !Shutdown Shutdown Shutdown Shutdown now"
FOUND IN "You should now Shutdown Shutdown Shutdown Shutdown Shutdown"
FOUND IN "ShutdownShutdownShutdownShutdownShutdown"
FAILED IN "OK, don't shutdown then..."
Works for me (W7)
Ah - perhaps you meant "occurs on 5 (or whatever) lines or "occurs 5 times in the file"...
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%i IN (f5shutdown.txt) DO (
ECHO %%i|FINDSTR /r .*Shutdown.*Shutdown.*Shutdown.*Shutdown.*Shutdown.* >NUL
IF ERRORLEVEL 1 ECHO FAILED IN "%%i"
IF NOT ERRORLEVEL 1 ECHO FOUND IN "%%i"
)
:: For 'shutdown' on n different lines: (assuming case-insensitive)
FOR /f %%i IN ('FIND /i /c "shutdown" ^<f5shutdown.txt') DO SET shutdowns=%%i
ECHO Second method: %shutdowns% lines found with "Shutdown"
:: For 'shutdown' occurrences (assuming case-insensitive)
SET /a shutdowns=0
FOR /f "delims=" %%i IN (f5shutdown.txt) DO (
SET line=%%i
CALL :findem
)
ECHO Third method found "Shutdown" %shutdowns% times
GOTO :eof
:findem
SET line=%line:"=%
SET after=%line:*shutdown=%
IF NOT DEFINED after SET /a shutdowns+=1&GOTO :EOF
if NOT "%line%"=="%after%" SET "line=%after%"&SET /a shutdowns+=1&GOTO findem
GOTO :eof
(I added an extra non-shutdown-containing line for the test. Found 8 lines and 28 occurrences)
This should detect when shutdown is on only 5 lines in the file.txt
#echo off
for /f %%a in ('find /i /c "shutdown" ^< "file.txt" ') do if %%a EQU 5 echo found it 5 times

How to check if directories listed in System PATH variable are valid?

This does not relate directly to my development project but I am curious none the less. Recently, after a lot of head-banging, I traced a build problem to an invalid entry in the System PATH variable. On my machine, it contains about 20 entries. I am guessing there has to be an easier way to verify the validity of each entry. Can anyone suggest a way to check this? Thanks for your time.
This code in a batch file (based on this answer) works for me:
#echo off
setlocal DisableDelayedExpansion
set "var=%PATH%"
set "var=%var:"=""%"
set "var=%var:^=^^%"
set "var=%var:&=^&%"
set "var=%var:|=^|%"
set "var=%var:<=^<%"
set "var=%var:>=^>%"
set "var=%var:;=^;^;%"
rem ** This is the key line, the missing quote is intention
set var=%var:""="%
set "var=%var:"=""%"
set "var=%var:;;="";""%"
set "var=%var:^;^;=;%"
set "var=%var:""="%"
set "var=%var:"=""%"
set "var=%var:"";""=";"%"
set "var=%var:"""="%"
setlocal EnableDelayedExpansion
for %%a in ("!var!") do (
endlocal
call :testdir "%%~a"
setlocal EnableDelayedExpansion
)
goto :eof
:testdir
if exist %1 echo OK: %1
if not exist %1 echo NOK: %1
Put the code into a text file, e.g. validatepath.bat.
When run, it should output something like:
OK: C:\Users\abcde
NOK: C:\this\is\no\dir