Description
A script that monitors the CPU use of a specified EXE, and will kill it if it exceeds a certain % CPU use for a configurable number of checks. Before you use this, you will need to create “config.ini” in the script directory, with the following contents:
"
[Settings]
Process_To_Monitor=prime95.exe
CPU_Alert_Percentage=75
Seconds_Between_Checks=3
Alerts_Before_Process_Close=15
Restart_Service_On_Close?=false
Service_To_Restart=
Use_Verbose_Logging?=false
[End]
"
Obviously changing the settings to meet your needs.
Source Code
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Res_Comment=Potential fix for small memory leak
#AutoIt3Wrapper_Res_Description=Monitors CPU Usage of a running exe.
#AutoIt3Wrapper_Res_Fileversion=1.0.0.10
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_SaveSource=y
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Res_requestedExecutionLevel=highestAvailable
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
;Application to Monitor CPU Use of Specified Process
;And Kill Process if CPU Use Exceeds Specified level
;Written by Steve Pavolko
;Aug 2014
;Updated Nov 2018
#include <Array.au3>
;Establish Current DateTime and a function to update it as needed
Global $date1 = @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC & ":: "
Global $dayclean = @YEAR & '-' & @MON & '-' & @MDAY
Global $dateclean = @YEAR & '-' & @MON & '-' & @MDAY & '_' & @HOUR & '_' & @MIN & '_' & @SEC & ' '
;Establish Global Vars
Global $config = @ScriptDir & '\config.ini'
Global $debugfile = @ScriptDir & '\debug_' & $dayclean & '.txt'
Global $kill = 0
Global $verboselog = 'temp'
Global $CPU_check1
Global $process1
Global $CPUmax
Global $tick
Global $CPUmaxCount
Global $restart
Global $service
Global $verboselog
Global $CPU_Use = 'temp'
Global $cpu2 = 'temp'
;==
;====
;===========================================================================================================================================================
Func _GetDate()
$date1 = @YEAR & '-' & @MON & '-' & @MDAY & '_' & @HOUR & ':' & @MIN & ':' & @SEC & ":: "
$dayclean = @YEAR & '-' & @MON & '-' & @MDAY
$dateclean = @YEAR & '-' & @MON & '-' & @MDAY & '_' & @HOUR & '_' & @MIN & '_' & @SEC & ' '
EndFunc
;===========================================================================================================================================================
;====
;==
;==
;====
;===========================================================================================================================================================
Func _Debug($dbgmsg)
_GetDate()
$debugfile = @ScriptDir & '\debug_' & $dayclean & '.txt'
FileWrite($debugfile, $dateclean & " " & $dbgmsg & @CRLF)
EndFunc
;===========================================================================================================================================================
;====
;==
;Write Init to Log for Ease of interpreting logs
_Debug('')
_Debug('')
_Debug('')
_Debug('==============================================')
_Debug('===============PROGRAM INIT===================')
_Debug('==============================================')
_Debug('')
_Debug('')
_Debug('')
;Declare Breakout Function
;==
;====
;===========================================================================================================================================================
Func _EndofScript()
_Debug('')
_Debug('')
_Debug('')
_Debug('==============================================')
_Debug('===============PROGRAM DONE===================')
_Debug('==============================================')
_Debug('')
_Debug('')
_Debug('')
EndFunc
;===========================================================================================================================================================
;====
;==
;Build out Function To get Process Properties
;==
;====
;===========================================================================================================================================================
Func _ProcessListProperties($Process = "", $sComputer = ".")
Local $sUserName, $sMsg, $sUserDomain, $avProcs, $dtmDate
Local $avProcs[1][2] = [[0, ""]], $n = 1
; Convert PID if passed as string
If StringIsInt($Process) Then $Process = Int($Process)
;~ If $verboselog = 'true' Then
;~ _Debug('Process1 ' & $Process)
;~ EndIf
; Connect to WMI and get process objects
$oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy, (Debug)}!\\" & $sComputer & "\root\cimv2")
If IsObj($oWMI) Then
; Get collection processes from Win32_Process
If $Process == "" Then
; Get all
$colProcs = $oWMI.ExecQuery("select * from win32_process")
ElseIf IsInt($Process) Then
; Get by PID
$colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & $Process)
Else
; Get by Name
$colProcs = $oWMI.ExecQuery("select * from win32_process where Name = '" & $Process & "'")
EndIf
;~ If $verboselog = 'true' Then
;~ _Debug('Process2 ' & $Process)
;~ EndIf
If IsObj($colProcs) Then
; Return for no matches
If $colProcs.count = 0 Then Return $avProcs
; Size the array
ReDim $avProcs[$colProcs.count + 1][10]
$avProcs[0][0] = UBound($avProcs) - 1
; For each process...
For $oProc In $colProcs
; [n][0] = Process name
$avProcs[$n][0] = $oProc.name
; [n][1] = Process PID
$avProcs[$n][1] = $oProc.ProcessId
; [n][2] = Parent PID
$avProcs[$n][2] = $oProc.ParentProcessId
; [n][3] = Owner
If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "\" & $sUserName
; [n][4] = Priority
$avProcs[$n][4] = $oProc.Priority
; [n][5] = Executable path
$avProcs[$n][5] = $oProc.ExecutablePath
; [n][8] = Creation date/time
$dtmDate = $oProc.CreationDate
If $dtmDate <> "" Then
; Back referencing RegExp pattern from weaponx
Local $sRegExpPatt = "\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:.*)"
$dtmDate = StringRegExpReplace($dtmDate, $sRegExpPatt, "$2/$3/$1 $4:$5:$6")
EndIf
$avProcs[$n][8] = $dtmDate
; [n][9] = Command line string
$avProcs[$n][9] = $oProc.CommandLine
; increment index
$n += 1
Next
Else
SetError(2); Error getting process collection from WMI
EndIf
; release the collection object
$colProcs = 0
; Get collection of all processes from Win32_PerfFormattedData_PerfProc_Process
; Have to use an SWbemRefresher to pull the collection, or all Perf data will be zeros
Local $oRefresher = ObjCreate("WbemScripting.SWbemRefresher")
$colProcs = $oRefresher.AddEnum($oWMI, "Win32_PerfFormattedData_PerfProc_Process" ).objectSet
$oRefresher.Refresh
; Time delay before calling refresher
Local $iTime = TimerInit()
Do
Sleep(20)
Until TimerDiff($iTime) >= 100
$oRefresher.Refresh
; Get PerfProc data
For $oProc In $colProcs
; Find it in the array
For $n = 1 To $avProcs[0][0]
If $avProcs[$n][1] = $oProc.IDProcess Then
; [n][6] = CPU usage
$avProcs[$n][6] = $oProc.PercentProcessorTime
$CPU_check1 = $oProc.PercentProcessorTime
; [n][7] = memory usage
$avProcs[$n][7] = $oProc.WorkingSet
ExitLoop
EndIf
Next
Next
Else
SetError(1); Error connecting to WMI
EndIf
$cpu2 = $avProcs[1][6]
;~ If $verboselog = 'true' Then
;~ _Debug('Process3 ' & $Process)
;~ EndIf
If $verboselog = 'true' Then
_Debug('CPU Time = ' & $CPU_check1)
EndIf
; Return array
$oWMI = 0
_ReduceMemory()
Return $avProcs
EndFunc ;==>_ProcessListProperties
;===========================================================================================================================================================
;====
;==
;==
;====
;===========================================================================================================================================================
Func _ReadConfig()
$process1 = IniRead($config, "Settings", "Process_To_Monitor", "NotFound")
$CPUmax = IniRead($config, "Settings", "CPU_Alert_Percentage", "NotFound")
$tick = IniRead($config, "Settings", "Seconds_Between_Checks", "NotFound")
$CPUmaxCount = IniRead($config, "Settings", "Alerts_Before_Process_Close", "NotFound")
$restart = IniRead($config, "Settings", "Restart_Service_On_Close?", "NotFound")
$service = IniRead($config, "Settings", "Service_To_Restart", "NotFound")
$verboselog = IniRead($config, "Settings", "Use_Verbose_Logging?", "NotFound")
If $restart = 'True' Or $restart = 'true' Or $restart = 'Yes' Or $restart = 'yes' Then
$restart = 'True'
EndIf
If $verboselog = 'True' Or $verboselog = 'true' Or $verboselog = 'Yes' Or $verboselog = 'yes' Then
_Debug('Monitoring '&$process1)
_Debug($CPUmax&'% Considered to be high CPU use.')
_Debug('Waiting '&$tick & ' seconds between checks.')
_Debug($process1 & ' Can hit ' & $CPUmax& '% ' &$CPUmaxCount & ' times before being terminated.')
_Debug('Will we restart a service after we close ' & $process1& '? '&$restart)
If $restart = 'True' Then
_Debug('Will restart '&$service)
EndIf
EndIf
If $verboselog = 'True' Or $verboselog = 'true' Or $verboselog = 'Yes' Or $verboselog = 'yes' Then
$verboselog ='true'
EndIf
If $verboselog = 'true' Then
_Debug('Config Read Complete')
EndIf
EndFunc
;===========================================================================================================================================================
;====
;==
_Debug('Initial Config Read.')
_ReadConfig()
;==
;====
;===========================================================================================================================================================
Func _CheckCPUofProcess()
$CPU_check1 = 'Default'
$CPU_use = _ProcessListProperties($process1,".")
If $verboselog = 'true' Then
_Debug('Check of CPU directly after function call: ' & $CPU_check1)
EndIf
$CPU_Use = $CPU_check1
If $verboselog = 'true' Then
_Debug($CPU_Use)
EndIf
EndFunc
;===========================================================================================================================================================
;====
;==
_Debug('Initial Process Check.')
_CheckCPUofProcess()
_Debug('Finished Initial Process Check.')
;==
;====
;===========================================================================================================================================================
Func _RestartService()
If $verboselog = 'true' Then
_Debug('Calling RestartService Function')
EndIf
If $restart = 'True' Then
RunWait("net stop" & $service, @SW_HIDE)
_Debug($service & ' stopped.')
RunWait("net start" & $service, @SW_HIDE)
_Debug($service & ' started.')
Else
If $verboselog = 'true' Then
_Debug('Not set to restart a service.')
EndIf
EndIf
EndFunc
;===========================================================================================================================================================
;====
;==
;==
;====
;===========================================================================================================================================================
;~ Func _KillProcessCall()
;~ _KillProcess()
;~ EndFunc
;===========================================================================================================================================================
;====
;==
;==
;====
;===========================================================================================================================================================
Func _ReduceMemory()
Local $ai_GetCurrentProcessId = DllCall('kernel32.dll', 'int', 'GetCurrentProcessId')
Local $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $ai_GetCurrentProcessId[0])
Local $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', $ai_Handle[0])
DllCall('kernel32.dll', 'int', 'CloseHandle', 'int', $ai_Handle[0])
Return $ai_Return[0]
EndFunc
;===========================================================================================================================================================
;====
;==
;==
;====
;===========================================================================================================================================================
Func _KillProcess()
;~ _CheckCPUofProcess()
$use1 = $CPU_Use
If $verboselog = 'true' Then
_Debug('CPU Use: ' & $use1 & '%')
EndIf
If $use1 = 'Default' or $use1 = 'default' Then
If $verboselog = 'true' Then
_Debug('Process likely not running. Sleeping for an interval.')
FileWrite($debugfile, @CRLF)
FileWrite($debugfile, @CRLF)
FileWrite($debugfile, @CRLF)
EndIf
$kill = 0
sleep($tick*1000)
EndIf
$use1 = Int($use1)
$CPUmax = Int($CPUmax)
$kill = Int($kill)
If $use1 >= $CPUmax Then
$kill = $kill + 1
If $verboselog = 'true' Then
_Debug('Current Kill Count: ' & $kill)
EndIf
ElseIf $use1 < $CPUmax Then
$kill = Int(0)
If $verboselog = 'true' Then
_Debug('Current Kill Count: ' & $kill)
EndIf
EndIf
If $kill >= $CPUmaxCount Then
_Debug($process1 & ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
_Debug($process1 & ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
_Debug($process1 & ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
_Debug($process1 & ' Has hit CPU Alert threshold and is being terminated.')
_Debug($process1 & ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
_Debug($process1 & ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
_Debug($process1 & ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
_Debug($use1)
$kill = 0
If $verboselog = 'true' Then
_Debug('Current Kill Count: ' & $kill)
EndIf
ProcessClose($process1) ;<----------------------------------------------------------------------------------------------------------------------------------------- THIS LINE KILLS THE EXE
_RestartService()
FileWrite($debugfile, @CRLF)
FileWrite($debugfile, @CRLF)
FileWrite($debugfile, @CRLF)
EndIf
sleep($tick*1000)
EndFunc
;===========================================================================================================================================================
;====
;==
;==
;====
;===========================================================================================================================================================
While True
If $verboselog = 'true' Then
_Debug('===================================')
_Debug('=======THATS A START, FOLKS!=======')
_Debug('===================================')
EndIf
If $verboselog = 'true' Then
_Debug('Loop Begin')
EndIf
If $verboselog = 'true' Then
_Debug('Reading Config')
EndIf
_ReadConfig()
sleep(50)
If $verboselog = 'true' Then
_Debug('Calling CheckCPUofProcess Function')
EndIf
_CheckCPUofProcess()
sleep(1000)
If $verboselog = 'true' Then
_Debug('Calling KillProcess Function')
EndIf
_KillProcess()
sleep(20)
;~ If $verboselog = 'true' Then
;~ _Debug('Calling RestartService Function')
;~ EndIf
;~ _RestartService()
If $verboselog = 'true' Then
_Debug('Calling Memory Reduction Function')
EndIf
_ReduceMemory()
If $verboselog = 'true' Then
_Debug('Loop End')
EndIf
If $verboselog = 'true' Then
_Debug('===================================')
_Debug('=======THATS A WRAP, FOLKS!========')
_Debug('===================================')
_Debug(@CRLF)
_Debug(@CRLF)
_Debug(@CRLF)
EndIf
WEnd
;===========================================================================================================================================================
;====
;==
FileWrite($debugfile, @CRLF)
FileWrite($debugfile, @CRLF)
FileWrite($debugfile, @CRLF)
OnAutoItExitRegister(_EndofScript())