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 (
Related
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"
)
I am trying create a batch file which pings a particular host and moves the results to a file with the current time stamp for every hour. I was able to do it continuously, but the I want to know whether there is any script with which I can set the interval for which it runs the ping command.
I am successfully able to print the time stamp, ping response and the able to change the name of the file with current time stamp, but it's happening continuously. I want to do it for a time interval like say for 4hrs continuous ping then move the results to a file.
please help
There is no sane way to do this with a command script only.
What I recommend is to write a script that performs the requested action once.
Use Windows Task Scheduler to call the script every hour.
What I've attempted is by NO means an ideal, much less precise method of doing what you desire (purely in batch), however with some tweaking and refining, or by serving as a potential route/template for similar scripts by more experienced batch scripters, I believe it may be useful:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1-2 delims=:" %%i in ('echo %time%') do (
set /a hour=%%i+4
set /a minute=%%j
set expected=!hour!:!minute!
echo !expected!
)
for /f "tokens=*" %%i in ('ping 192.168.1.1 -n 1') do (echo %%i>pinglog.txt && goto PING)
:PING
for /f "tokens=1-2 delims=:" %%i in ('echo %time%') do (
set current=%%i:%%j
echo !current!
)
if !current!==!expected! (
goto EOF
) else (
for /f "tokens=* skip=2" %%i in ('ping 192.168.1.1 -n 2 -w 30000') do (
echo %date% %time% %%i>>pinglog.txt && goto PING
)
)
Control the hour or minute interval by adding the relevant value to either, in the lines:
set /a hour=%%i+4 rem Here I've added 4 hours
set /a minute=%%j
Remove the echo !expected! and echo !current! lines if you don't wish to see the temporal progression in the cmd output, which can be minimised while the script is running.
I do not know if this question was asked before, but here goes:
Is there a way to write a batch script such that it continuously monitors the cpu usage % of a certain executable program until the cpu hits 0%? Say we have a program called xyz.exe, which currently uses up about 2-4% of cpu according to the task manager. After a certain time the cpu hits 0%. I've tried using tasklist command as follows, but was unable to tweak it for cpu purposes:
#echo off
:loop
tasklist | "xyz"
if errorlevel 1 (
echo xyz still running
goto loop
) else (
goto next
)
:next
xyz completed
with typeperf "\Process(xyz)\% Processor Time" you can check the processor usage of xyz:
#echo off
:check
for /f "skip=2 tokens=2 delims=," %%c in ('typeperf "\Process(xyz)\%% Processor Time" -sc 1') do (
set cpu_usage=%%~c
goto :break
)
:break
echo %cpu_usage%
set cpu_usage=%cpu_usage:.=%
:: 1 is set in the front to avoid octal comparison
if 1%cpu_usage% LSS 11000000 (
goto :check_process
) else (
goto :check
)
:: sleep for 1 second
pathping 127.0.0.1 -n -q 1 -p 1000 >nul 2>&1
:check_process
QPROCESS * | find /i "xyz" >nul 2>&1 && (
echo process xyz is running
) || (
echo process xyz is not running
)
endlocal
TYPEPERF ; LOGMAN
Use this
For /f "skip=1" %%a in ('wmic cpu get loadpercentage LoadPercentage') do echo %%a
This method simply parses the standard output of wmic command to the for body and an instance variable is created from it ... Hope it helps
Not sure what permissions are needed, the following powershell pipe will query via WMI (the Get-Process powershell object seems not to calculate percentage):
gwmi Win32_PerfFormattedData_PerfProc_Process |
where {$_.Name -eq "jusched"} | select IDProcess,Name,PercentProcessorTime
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.
Having tried variations of the following, and with further additional code, what is wrong here? Thanks!
#echo off
goto checkmemorystatus
:checkmemorystatus
for /f "skip=1" %%p in ('wmic os get freephysicalmemory') do (
set m=%%p
if %m% LSS <threshold> (start echo FREE RAM ALERT: %m% & PING 1.1.1.1 -n 1 -w 60000 >NUL)
goto checkmemorystatus
)
no need for delayed expansion (as there is no need for an additional variable):
#echo off
:checkmemorystatus
PING localhost -n 2 -w 60000 >NUL
for /f "skip=1" %%p in ('wmic os get freephysicalmemory') do (
if %%p leq 700000 ( echo FREE RAM ALERT: %%p ) else (echo FREE RAM ok : %%p)
goto checkmemorystatus
)
(the code is basically taken from mihai_mandis)
wmic gives you more lines than you want. You already ignored the first line with skip. The above code breaks the for-loop after one run and to ignore the following lines. ( I added a "Free RAM ok" for testing purposes - you may want to delete it)
At the beginning of the script set delayed expansion:
setlocal EnableDelayedExpansion
This will allow you to access variables in for loops in format !var_name!
2.Do not use goto statements inside for block. This will cause for break.
#echo off
setlocal EnableDelayedExpansion
:checkmemorystatus
for /f "skip=1" %%p in ('wmic os get freephysicalmemory') do (
set mm=%%p
if !mm! LSS <threshold> (
start echo FREE RAM ALERT: !mm!
PING localhost -n 1 -w 60000 >NUL
)
)
goto :checkmemorystatus