Here or there I have found Cleanmgr.exe and Ccleaner to hang. When they do, typically the CPU usage is upwards of 90%+. The hangs are intermittent and hard to reproduce, but when they hang, task manager has reported running them running for over 8 hours. 99% CPU usage is typical for a few seconds.
So I wrote a short little vbScript to run the apps, then kill it if it takes too long - I'm thinking no more than 3 minutes per app. FYI, I'm running out of box, from WinXp to 8.1, so I really only have vbScript and the command line.
First attempt appeared successful, but then I found I had to apply a second test, again with another timer, however, now I find my script doesn't exit at all when Cleanmgr or CCleaner hangs.
This started simple, and now it's nuts. I'm hoping someone out here can help me. I think the issue is, the process is chewing up my CPU, so the timer check in my script can't run...
It occurred to me, I'm calling this from a cmd file using cScript - could there be some issue there?
Is there a way to track the process time rather than from a timer? Create a thread higher priority than the process so it can terminate when it hangs? Maybe I have bug in my code? Help please, I'm going nuts. Thank you.
Option Explicit
On Error Goto 0
Dim wshShell, sysPath, waitTime, i, str, masterTimer, mElapsed, slp
Dim apps(), paths(), params()
Set wshShell=WScript.CreateObject("wScript.Shell")
sysPath = wshShell.ExpandEnvironmentStrings("%SystemRoot%")
waitTime = 90
slp = 2255
ReDim apps(2)
ReDim paths(2)
ReDim params(2)
apps(0) = "cleanmgr.exe"
paths(0) = sysPath&"\System32"
params(0) = "/SageRun:101"
apps(1) = "ccleaner.exe"
paths(1) = "C:\Program Files\ccleaner"
params(1) = "/AUTO"
apps(2) = "ccleaner64.exe"
paths(2) = "C:\Program Files\ccleaner"
params(2) = "/AUTO"
For i=LBound(apps) to UBound(apps)
str="cmd.exe /C taskkill.exe /im " & apps( i ) & " /f /t"
wshShell.run str
str="cmd.exe /C taskkill.exe /im " & apps( i ) & " /f"
wshShell.run str
str="cmd.exe /C tskill.exe " & apps( i ) & " /a /v"
wshShell.run str
WScript.Sleep slp
masterTimer = Timer
mElapsed = 0
RunCleaner paths(i),apps(i),params(i)
str="cmd.exe /C taskkill.exe /im " & apps( i ) & " /f /t"
wshShell.run str
str="cmd.exe /C taskkill.exe /im " & apps( i ) & " /f"
wshShell.run str
str="cmd.exe /C tskill.exe " & apps( i ) & " /a /v"
wshShell.run str
Set Str=Nothing
Wscript.sleep slp
Next
ReDim apps(0)
ReDim paths(0)
ReDim params(0)
Erase apps
Erase paths
Erase params
Set slp=Nothing
Set sysPath=Nothing
Set wshShell=Nothing
Set waitTime=Nothing
WScript.Quit(0)
Public Sub RunCleaner( strPath, prog, args )
Dim objFSO, objWMIService, objProcess, objStartup, objConfig, colMonitoredProcesses, objLatestProcess
Dim intProcessID, erReturn, processes, proc
Dim fullPath, elapsed, startTime, running
Set objFSO=CreateObject( "Scripting.FileSystemObject" )
fullPath = "" & strpath & "\" & prog
If objFSO.FileExists( fullPath ) Then
Set objWMIService= GetObject( "winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2" )
Set objProcess = GetObject( "winmgmts:root\cimv2:Win32_Process" )
Set objStartup = objWMIService.Get( "Win32_ProcessStartup" )
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = 1
elapsed = -1 * slp
startTime = Timer
Wscript.sleep slp
erReturn = objProcess.Create ( fullPath & " " & args, Null, objConfig, intProcessID )
Set colMonitoredProcesses = objWMIService. _
ExecNotificationQuery( "select * From __InstanceDeletionEvent " _
& " within 1 where TargetInstance isa 'Win32_Process'" )
Do While ( ( elapsed < waitTime ) And ( ( mElapsed ) < waitTime ) )
Set objLatestProcess = colMonitoredProcesses.NextEvent
If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
Exit Do
End If
elapsed = Timer - startTime
mElapsed = Timer - masterTimer
Loop
WScript.sleep slp
running = True
Do While ( ( running ) And ( elapsed < waitTime ) And ( mElapsed < waitTime ) )
SET processes = GetObject( "winmgmts:" )
running = False
elapsed = ( Timer - startTime ) / 2
For Each proc in processes.InstancesOf( "Win32_Process" )
If ( StrComp( LCase( proc.Name ), LCase( prog ), vbTextCompare ) = 0 ) Then
running = True
Exit For
End If
Next
Set processes=Nothing
mElapsed = ( Timer - masterTimer ) / 2
Loop
WScript.sleep slp
fullPath = "cmd.exe /C taskkill.exe /im " & prog & " /f /t"
wshShell.run fullPath
fullPath = "cmd.exe /C taskkill.exe /im " & prog & " /f"
wshShell.run fullPath
fullPath = "cmd.exe /C tskill.exe " & prog & " /a /v"
wshShell.run fullPath
Set objWMIService=Nothing
Set objProcess=Nothing
Set objStartup=Nothing
Set objConfig=Nothing
Set objProcess=Nothing
Set erReturn=Nothing
Set intProcessID=Nothing
Set colMonitoredProcesses=Nothing
Set elapsed=Nothing
Set startTime=Nothing
Set objLatestProcess=Nothing
Set running=Nothing-1 * slp
Set proc=Nothing
Set fullPath=Nothing
End If
Set objFSO=Nothing
End Sub
Your script seems a bit complex for what it needs to do. Try this out.
The exes are executed consecutively. If any are running for longer than 3 minutes then they're terminated via taskkill. If you want to do away with WMI queries altogether (which is probably where your script is having to fight for CPU) you could simply wait three minutes for each exe you start and then send a taskkill without checking whether it's still running. You could also do a tasklist rather than a WMI query.
Dim fso, shl, wmi
Set fso = CreateObject("Scripting.FileSystemObject")
Set shl = CreateObject("WScript.Shell")
Set wmi = GetObject("winmgmts:\\.\root\cimv2")
Dim app1, app2, app3, apps()
ReDim apps(-1)
app1 = fso.BuildPath(shl.ExpandEnvironmentStrings("%SYSTEMROOT%"), "System32\cleanmgr.exe")
app2 = "C:\Program Files\ccleaner\ccleaner.exe"
app3 = "C:\Program Files\ccleaner\ccleaner64.exe"
If fso.FileExists(app1) Then AddApp app1, "/SageRun:101"
If fso.FileExists(app2) Then AddApp app2, "/AUTO"
If fso.FileExists(app3) Then AddApp app3, "/AUTO"
If UBound(apps) < 0 Then WScript.Quit ' None of the programs exist
Dim apptorun, starttime, running, process
For Each apptorun In apps
starttime = Now
process = fso.GetFile(apptorun.exe).Name
shl.Run apptorun.exe & " " & apptorun.param, 0, False
Do While 1
WScript.Sleep 5000
Set running = wmi.ExecQuery("select * from win32_process where name = """ & process & """")
If running.Count = 0 Then Exit Do
If DateDiff("n", starttime, Now) > 3 Then
shl.Run "taskkill /f /im " & process, 0, True
Exit Do
End If
Loop
Next
Sub AddApp(app, arg)
ReDim Preserve apps(UBound(apps) + 1)
Set apps(UBound(apps)) = New program
apps(UBound(apps)).exe = app
apps(UBound(apps)).param = arg
End Sub
Class program
Dim exe, param
End Class