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
Related
This code returns the disk size and space in GB. The problem is, it's only using C and i have to hard-code it.
What i'm trying is, it should iterate over all of the disks and i shouldn't have to write the disk part myself. All of my experiments were failure, i couldn't solve.
for /f "tokens=1-3" %%n in ('"WMIC LOGICALDISK GET Name,Size,FreeSpace | find /i "C:""') do set free=%%n& set total=%%p
set free=%free:~0,-3%
set /a free=%free%/1049
set total=%total:~0,-3%
set /a total=%total%/1049
set /a free=%free%/1024
echo C: Space Free- %free% GB
set /a total=%total%/1024
echo C: Space total- %total% GB
Something like this? It is a little sloppy but I think it does what you are asking for using the batch you (mostly) wrote.
I am using a batch function to get the variables out of the for /f loop. You could have also used delayed expansion. I find the whole !syntax! annoying but it seems that most people prefer it to batch functions.
#echo off
for /f "tokens=1-3" %%n in ('"WMIC LOGICALDISK GET Name,Size,FreeSpace"') do call :calculate "%%n" "%%o" "%%p"
goto :EOF
:calculate
set free=%~1
set drive=%~2
set total=%~3
if "%drive%"=="" goto :EOF
if not "%drive:~1%"==":" goto :EOF
echo ---- information for drive %drive% ----
set free=%free:~0,-3%
set /a free=%free%/1049
set total=%total:~0,-3%
set /a total=%total%/1049
set /a free=%free%/1024
echo Free- %free% GB
set /a total=%total%/1024
echo Total- %total% GB
goto :EOF
Below is part of a script i've previously written to grab drive information that is echoed to screen, written to a text file and also into a CSV.
#echo off
set "pathBackup=C:\backup"
set "infoFileName=%computername%_DriveSize.txt"
set "csvFile=All_DriveSizes.csv"
::Fix for CSV format output error on some systems
if exist "%WINDIR%\System32\wbem\en-us\csv.xsl" (
set csvformat="%WINDIR%\System32\wbem\en-us\csv"
) else (
set csvformat=csv
)
:: Get Drive Partition information
echo. - Looking for Drive sizes
setlocal EnableDelayedExpansion
for /f "skip=2 tokens=2-5 delims=," %%a in ('wmic logicaldisk where (DriveType^="3"^) get DeviceID^,FreeSpace^,Size^,VolumeName /format:%csvformat%') do (
set "diskID=%%a"
set "diskSpace=%%b"
set "diskSize=%%c"
set "diskName=%%d"
set /a diskSize1=!diskSize:~0,-4! / 107374
if "0"=="!diskSize1!" (
set /a diskSize1=!diskSize! / 1048576
set diskSize1=0.!diskSize1:~0,-2!
)
set /a diskSpace1=!diskSpace:~0,-4! / 107374
if "0"=="!diskSpace1!" (
set /a diskSpace1=!diskSpace! / 1048576
set diskSpace1=0.!diskSpace1:~0,-2!
)
set driveSizes=!driveSizes!"[%%a] %%d (!diskSize1!:!diskSpace1!)",
)
endlocal&if "_%~2"=="_" (set driveSizes=%driveSizes:~0,-1%)
:: Create non CSV variable for use in CSV file creation
set driveSizescsv=%driveSizes:"=%
set driveSizescsv="%driveSizescsv%"
The bit that echos to screen and writes to text file...
echo PC Drives : [Drive] Label (Size GB:Free GB)>>"%pathBackup%\%infoFileName%"
echo PC Drives : [Drive] Label (Size GB:Free GB)
:: Write individual drives one at a time
setlocal EnableDelayedExpansion
for %%i in (%driveSizes:,= %) do (
set driveSizes1=%%i
echo. !driveSizes1:"=!
set driveSizes2=!driveSizes1:"=!
echo. !driveSizes2!>>"%pathBackup%\%infoFileName%"
)
endlocal
The bit that writes to a csv
echo %computername%,%driveSizescsv% >>"%pathBackup%\%csvfile%"
Output example..
PC Drives : [Drive] Label (Size GB:Free GB)
[C:] Windows (79:42)
[D:] Database Volume (599:90)
[E:] Log File (39:31)
As the wmic command can take a while, and arithmetic can be particularly tricky in pure batch, here are a couple of additional options for you, which leverage other built-in scripting languages:
This complete batch-file uses powershell:
#"%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoP^
"[System.IO.DriveInfo]::GetDrives()|?{$_.IsReady -Eq $True}|"^
"Select #{N='Drive';E={$_.Name.TrimEnd('\')}},"^
"#{N='Size (GiB)';E={[Double]('{0:N2}' -F ($_.TotalSize/1GB))}},"^
"#{N='Free (GiB)';E={[Double]('{0:N2}' -F ($_.AvailableFreeSpace/1GB))}}|FL
#"%__AppDir__%timeout.exe" /T 5 /NoBreak>NUL
And this even quicker batch-file uses the vbscript engine of wsh:
<!-- :
#"%__AppDir__%cscript.exe" //NoLogo "%~f0?.wsf"
#"%__AppDir__%timeout.exe" /T 5 /NoBreak>NUL
#Exit /B
-->
<Job><Script Language="VBScript">
Set o=CreateObject("Scripting.FileSystemObject")
For Each Drv In o.Drives:If Drv.IsReady=True Then
WScript.Echo "Drive="&Drv.DriveLetter&":"&VBCrLf&_
"Size="&Round(Drv.TotalSize/1073741824,2)&" GiB"&VBCrLf&_
"Free="&Round(Drv.FreeSpace/1073741824,2)&" GiB"
End If:Next
</Script></Job>
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"
)
The idea is that a new device enters my network and a script running in the background can run a command to back it up, SyncToy for example (cd Program Files/SyncToy SyncToyCmd.exe -r).
I've run into scripts from similiar questions (How to check if ping responded or not in a batch file)
#setlocal enableextensions enabledelayedexpansion
#echo off
set ipaddr=%1
set oldstate=neither
:loop
set state=down
for /f "tokens=5,7" %%a in ('ping -n 1 !ipaddr!') do (
if "x%%a"=="xReceived" if "x%%b"=="x1," set state=up
)
if not !state!==!oldstate! (
echo.Link is !state!
set oldstate=!state!
)
ping -n 2 127.0.0.1 >nul: 2>nul:
goto :loop
endlocal
However I can't figure out how to run the command when the state changes to "up" as an exception in the loop, I also only want to run it once, adding a condition of once every 12 hours maybe.
Is this as simple as placing the command inside the block that tests for receipt? I do not understand how SyncToy would know the IP address.
for /f "tokens=5,7" %%a in ('ping -n 1 !ipaddr!') do (
if "x%%a"=="xReceived" if "x%%b"=="x1," (
set state=up
PUSHD "%ProgramFiles%/SyncToy"
SyncToyCmd.exe -r
POPD
)
)
The code below will write the computer name and ip address to file, but I would like it to also write the name of the computers it cannot ping with a fail next to it. I have no idea how I would modify the batch file to do this.
#echo off
Echo Pinging list...
set ComputerList=list.txt
Echo Computername,IP Address>Final.csv
setlocal enabledelayedexpansion
for /f "usebackq tokens=*" %%A in ("%ComputerList%") do (
for /f "tokens=3" %%B in ('ping -n 1 -l 1 %%A ^|findstr Reply') do (
set IPadd=%%B
echo %%A,!IPadd:~0, -1!>>Results.csv
))
pause
You could use errorlevel set by findstr to substitute return string(s) if 'Reply' is not found:
('ping -n 1 -l 1 %%A ^|findstr Reply ^|^| echo Not found Failed:')
where || (escaped here because of for context with ^) means execute only if previous command failed.
As a side note, you should be aware that ping messages are system language dependent (they are translated to language of OS) so 'Reply' as success indicator works only for English versions.
This may not be directly what you are looking for, but I had a similar task: run ping and report success or failure. I'll leave extracting the IP address to you - seeing as you have already done it.
The problem with ping is that it returns success upon name resolution, whether packets get lost or host is unreachable (will report 0% Loss) is irrelevant.
FOR %%a IN (
google.com
a.b.c.d
) DO #FOR /F "delims=" %%p IN (
'PING -w 100 -n 1 %%a ^| findstr ^"Reply Request fail name^"'
) DO #(
ECHO "%%p" | FINDSTR TTL >2 && echo %%a, success, %%p || echo %%a, failed, %%p
) >> Results.csv
Logic: Ping once, filter only lines with the one of the words listed. If TTL exists in resulting line (output to STDERR or NUL to avoid output pollution) echo success, else echo failed.
I'm on English Windows, words will have to be adjusted for other languages.
EDIT:
FOR %%a IN (
google.com
a.b.c.d
) DO #FOR /F "delims=" %%p IN ('PING -n 1 %%a ^| findstr TTL ^|^| echo Failed') DO #(
ECHO "%%p" | FINDSTR TTL >2 && (for /f "tokens=3" %%b IN ("%%p") do #echo %%a, %%b) || echo %%a, failed, %%p
)
Less dependant on language, works only for IPv4, added IP extraction.
Filter ping output for TTL, set output to "Failed" if TTL not found.
If output string contains TTL, extract IP and echo host and IP, else echo host name and output string.
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 (