Math in a Batch File - windows

I want to use
wmic NIC where NetEnabled=true get Name, Speed
to get the NIC speed.
However, I want to do some Math on the Speed to get a more sensible figure, i.e. 1000Mbps or 100Mbps. How can you do such Math in Batch?

You can do simple math in batch-files.
You can use set /a var=1+1 and set /a var=%var%+1 etc.
In your example it would be (for just the speed):
#echo off
for /f "tokens=2 delims==" %%a in ('wmic nic where NetEnabled^=true get speed /value ^| find /i "speed"') do set /a speed=%%a
echo Speed in bytes: %speed% Bps
set /a speed=%speed%/1024
echo Speed in kilobytes: %speed% Kbs
set /a speed=%speed%/1024
echo Speed in megabytes: %speed% Mbs

Related

How to get the number of physical and logical cores in a batch file on a dual socket machine?

WMIC CPU Get NumberOfCores,NumberOfLogicalProcessors gets me most of what I want, but how do I store the combined output into a variable?
for /f "delims=" %%a in ('"WMIC CPU Get NumberOfCores,NumberOfLogicalProcessors /value"') do set /a "_%%a"
set _
Works for single socket machines only. The WMIC command returns cpu info on separate lines, i.e.
>WMIC CPU Get NumberOfCores,NumberOfLogicalProcessors /value
NumberOfCores=24
NumberOfLogicalProcessors=48
NumberOfCores=24
NumberOfLogicalProcessors=48
#echo off
setlocal
set /A "_NumberOfCores=_NumberOfLogicalProcessors=0"
for /F "tokens=1,2 delims==" %%a in ('WMIC CPU Get NumberOfCores^,NumberOfLogicalProcessors /value') do if "%%b" neq "" set /A "_%%a+=%%b"
set _
Note that wmic command output lines terminated in CR+CR+LF ASCII characters, even the empty lines, so it is necessary to check if the %%b part exists to avoid to process empty lines.
This will do it:
for /f "tokens=2,3 delims=," %%a in ('WMIC CPU Get NumberOfCores^,NumberOfLogicalProcessors /value /format:csv') do set "both=Cores=%%a Processors=%%b"
/format:csv changes up the format some, making it easier for us to manipulate, which I did in the above command.

VBS: InputBox position doesn't correlate properly with screen size retrieved from WMIC

This batch code retrieves the screen width and screen height, in the format "WIDTH x HEIGHT"
#echo off
setlocal
for /f %%A in ('wmic path Win32_VideoController get CurrentHorizontalResolution^,CurrentVerticalResolution /value ^| find "="') do set "%%A"
echo %CurrentHorizontalResolution% x %CurrentVerticalResolution%
Now, given the output of the above returns "1920 x 1080", the below VBScript Code should spawn an InputBox in the lower-right corner of the screen.
InputBox "","Title","",1920,1080
However, it doesn't. This is because the PosX and PosY variables in the VBS InputBox function are measured in Twips instead of Pixels.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.interaction.inputbox?view=netframework-4.8
Is there any way to convert Pixels to Twips with only Batch and VBScript?
I came across a solution while creating an error message customization program. The idea is to take a second pair of values from WMIC, known as "PixelsPerXLogicalInch" and "PixelsPerYLogicalInch"
for /f %%A in ('wmic path Win32_DesktopMonitor get PixelsPerXLogicalInch^,PixelsPerYLogicalInch /value ^| find "="') do set "%%A"
echo %PixelsPerXLogicalInch% x %PixelsPerYLogicalInch%
This will output a conversion factor for converting pixels to inches. Since a twip is just 1/1440th of an inch, dividing these values into 1440 will result in the number of twips per pixel.
for /f %%A in ('wmic path Win32_DesktopMonitor get PixelsPerXLogicalInch^,PixelsPerYLogicalInch /value ^| find "="') do set "%%A"
set /a TwipsPerPixelX=1440/%PixelsPerXLogicalInch%
set /a TwipsPerPixelY=1440/%PixelsPerYLogicalInch%
echo %TwipsPerPixelX% x %TwipsPerPixelY%
Now, just apply those conversion factors to the positional calculations with a little multiplication.
#echo off
setlocal
for /f %%A in ('wmic path Win32_VideoController get CurrentHorizontalResolution^,CurrentVerticalResolution /value ^| find "="') do set "%%A"
for /f %%A in ('wmic path Win32_DesktopMonitor get PixelsPerXLogicalInch^,PixelsPerYLogicalInch /value ^| find "="') do set "%%A"
set /a TwipX=%CurrentHorizontalResolution%*(1440/%PixelsPerXLogicalInch%)
set /a TwipY=%CurrentVerticalResolution%*(1440/%PixelsPerYLogicalInch%)
echo %TwipX% x %TwipY%
The output values from this set of commands will produce an InputBox just beyond the screen's bottom right corner (as windows are positioned from the top left corner.)
Taking all that into account, you could create a script that spawns an InputBox in a random position on-screen. That, or prompt the user for a position value, or even use this in your own CMD/VBS applications to position your Input Boxes more accurately.
<!-- :
#echo off
setlocal
for /f %%A in ('wmic path Win32_VideoController get CurrentHorizontalResolution^,CurrentVerticalResolution /value ^| find "="') do set "%%A"
for /f %%A in ('wmic path Win32_DesktopMonitor get PixelsPerXLogicalInch^,PixelsPerYLogicalInch /value ^| find "="') do set "%%A"
set /a RandX=(%Random%*%CurrentHorizontalResolution%/32768)*(1440/%PixelsPerXLogicalInch%)
set /a RandY=(%Random%*%CurrentVerticalResolution%/32768)*(1440/%PixelsPerYLogicalInch%)
start /b cscript //nologo "%~f0?.wsf" "%RandX%" "%RandY%"
exit /b
-->
<job><script language="VBScript">
InputBox "","Randomly-Positioned Input Box","",Wscript.Arguments(0),Wscript.Arguments(1)
</script></job>

Script to run a program at a certain CPU load

I have tried for like 3 hours now, with multiple codes similar to this:
wmic cpu get loadpercentage > Load.txt
findstr "%random:~,1%" Load.txt > Load1.txt
set load=<Load1.txt
if %load%==" 2 7 " echo yes
pause
But they all run in to a similar problem, the output of wmic cpu get loadpercentage:
LoadPercentage
56
The format just doesn't allow it to be put into a variable, so I can't check it for anything. Perferably, I would like it to be done in Windows CMD and/or Powershell.
Thanks for the help!
EDIT:
Thanks to #lit for the code, here's my final code that works perfectly:
:: To find the "GUID" or the codes for each power plan, run the command in CMD "powercfg -list".
set HighPerformanceMode=8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
set PowerSaverMode=a1841308-3541-4fab-bc81-f71556f20b4a
:loop
SETLOCAL ENABLEDELAYEDEXPANSION
SET "load="
FOR /F "usebackq skip=1 tokens=*" %%f IN (`wmic cpu get loadpercentage`) DO (
IF "!load!" EQU "" (
set "load=%%~f"
)
)
if "%load%" geq "65" (
ping localhost -n 2 >nul
if "%load%" geq "65" (
%systemroot%\System32\powercfg.exe /setactive %HighPerformanceMode%
)
) else (
if "%load%" lss "25" (
ping localhost -n 2 >nul
if "%load%" lss "25" (
%systemroot%\System32\powercfg.exe /setactive %PowerSaverMode%
)
)
)
endlocal
ping localhost -n 3 > nul
goto loop
Make sure you change the HighPerformanceMode and PowerSaverMode to have your computer specific power plans. You can find the codes by doing powercfg -list in cmd.
I then made a separate short script that just has "C:\Load Batch\Load Batch.bat" in it, but you have to change it to wherever the main script is. Then I used a program called "BAT to EXE converter" and put it in Ghost Mode, and put the newly made .exe program into my startup folder.
EDIT 2:
I don't believe that my question is a duplicate, the linked question is about getting CPU and RAM usage for what appears to be just to view it, while my question is about getting the load percentage as a pure text form to be used in a script. I am aware of it only testing for one CPU core, but as one goes up it is very likely that the others have similar loads. I had searched this site for code that would separate the "LoadPercentage" text when wmic cpu get loadpercentage is ran, because I couldn't set it into a variable that way.
It is likely that the problem is that wmic output is in Unicode. How about going with PowerShell?
Get-CimInstance -ClassName CIM_Processor | select LoadPercentage
I am not sure from the question about what needs to run.
The typical fallback of cmd shell programmers is usually something like:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "X="
FOR /F "usebackq skip=1 tokens=*" %%f IN (`wmic cpu get loadpercentage`) DO (
IF "!X!" EQU "" (
set "X=%%~f"
)
)
ECHO X is %X%
EDIT:
Actually, there will be a LoadPercentage emitted for each core. You probably want the arithmetic mean (average) of them.
Get-CimInstance -ClassName CIM_Processor |
Measure-Object -Property LoadPercentage -Average |
Select Average
Doing this in a cmd script would involve summing the LoadPercentage values and dividing by the count of them.
SET /A TOTAL=0
SET /A CORE_COUNT=0
FOR /F "usebackq skip=1" %%t IN (`type NUL ^| wmic /node:"%SERVER_NAME%" cpu get loadpercentage ^| findstr .`) DO (
IF "%%t" NEQ "" (
SET /A TOTAL=!TOTAL! + %%t
)
SET /A CORE_COUNT=!CORE_COUNT! + 1
)
SET /A AVG_UTILIZATION=%TOTAL% / %CORE_COUNT%
ECHO Number of cores: %CORE_COUNT%
ECHO Total CPU utilisation: %TOTAL%
ECHO Average CPU utilisation: %AVG_UTILIZATION%%%
Although writing to a (temporary) file and reading it back with set /p is a possible and valid way, the usual way of getting the output of a command into a variable in cmd is a for /f loop:
for /f "" %%a in ('wmic cpu get loadpercentage /value ^|find "="') do set /a "%%a"
echo %loadpercentage%
As in lits answer, a find (or findstr) command is used to convert the Unicode output of wmic to a "cmd compatible" format.
I use the /value parameter to get an outputformat that's easier to parse and set /a to get a numeric value (no need to mess with spaces).
The benefit of using /value is, you can easily get more than one parameter from the same wmic command:
for /f "delims=" %%a in ('"wmic cpu get Caption,CurrentClockSpeed,ExtClock,L2CacheSize /value |findstr = "') do set "_%%a"
set _
Enclosing the complete command in quotes removes the need of escaping special chars. Of course this works only, if you don't need quotes in the commandstring itself.
(without quoting:
for /f "delims=" %%a in ('wmic cpu get Caption^,CurrentClockSpeed^,ExtClock^,L2CacheSize /value ^|findstr = ') do set "_%%a"
)

Get Multiple NICs Speed 10/100/1000

I have the following batch file, however, it freaks out if you have more than one NIC enabled and spits out output of Speed for the first NIC it reports, but for any more, it reports
Speed = Missing Operand
How can I fix this?
#echo off
for /f "tokens=2 delims==" %%a in ('wmic nic where NetEnabled^=true get speed /value ^| find /i "speed"') do set /a speed=%%a
set /a speed=((%speed%/1024)/1024)
echo Speed in megabytes: %speed% Mbps
pause
In addition, why doesn't it work in batch file execution without the '^' before the '=' and '|'
#ECHO OFF &SETLOCAL
for /f "tokens=2 delims==" %%a in ('wmic nic where NetEnabled^=true get speed /value ^| find /i "speed"') do set "speed=%%a"
set /a speed=speed/1048576 2>nul
if %speed% neq 0 (echo Speed in megabytes: %speed% Mbps) else echo No speed available.
You need to escape = and | in the for-loop, no matter if batch or cmd window. It's because it's in the for-loop.

Using set for numeric value (batch)

I am attempting to write a batch program that will monitor cpu usage and stop a virus scan if cpu usage is high. It will then restart the scan when cpu usage drops.
ECHO Checks if the total CPU usage is greater than 10%
SET scanEnd=0
tasklist /FI "IMAGENAME eq scan32.exe" 2>NUL | find /I /N "scan32.exe">NUL
IF "%ERRORLEVEL%"=="0" (
ECHO Program is running
wmic cpu get loadpercentage /value
FOR /f "tokens=2-3 delims==" %%b in ('wmic cpu get loadpercentage /value') do (
echo %%b >> tempfile.txt
echo removed %%a)
SET /a load < tempfile.txt
DEL tempfile.txt
ECHO Load is "%load%"
IF load GEQ 10 (
ECHO High cpu usage
TSKILL scan32
SET scanEnd=1
))
PAUSE
IF "1" == "%scanEnd%" (
ECHO Scan not finished
IF load LSS 10 (
ECHO Restarting scan
"C:\Program Files\McAfee\VirusScan Enterprise\scan32.exe"
SET scanEnd=0))
ECHO End of program
PAUSE
wmic returns the cpu usage in the form LoadPercentage=0 (or other number). I filter this with the for loop and assign the digit to load. For reasons I do not understand, there is something wrong with the assignment. I am unable to echo the value (displays "") and no matter how I define high cpu usage, load passes the IF GEQ statement. Even a 0% load is apparently greater than 10. I know the problem is with set because I checked the tempfile.txt and it is filtered correctly, but I still have no idea why it's wrong.
Thanks for any help.
you assumed that SET command can read from stdin which is not the case.
You might simply assign the FOR variable into a new variable.
Try this
for /f "tokens=2-3 delims==" %%a in ('wmic cpu get loadpercentage /value') do (
set /a load=%%a
)
and then
if %load% geq 10 (
echo load greater than 10%
)
but beware of the assignments inside FOR loops. You may need to enable delayed expansion for them to work correctly, in case there are more than one assignment in the loop. Eventhough this is not your case, you'd just need to adjust
setlocal enabledelayedexpansion
and then refer to it using this optional syntax
if !load! geq 10 (

Resources