VBScript Help - Top 10 Processes by CPU

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
I've spent well over 12 hours searching and fighting with this travesty of a programming language to get this to work. Unfortunately, I'm stuck having to do this with just VBScript.

The major problems I'm running into are an inability to pull the proper CPU data, no array sort (will have to make one on my own apparently), no array slice (will have to make one on my own, fml).

I've been trying to get the data using WMI's Win32_PerfFormattedData_PerfProc_Process with the "Name" and "PercentProcessorTime" fields. Apparently you have to repoll the data twice just for it to give you valid information - If you just poll once it returns all zeros or NULL for PercentProcessorTime - which explains the retardation of this snippet:
Code:
objRefresher.Refresh
WScript.Sleep(1000)
objRefresher.Refresh
If I go for less than 1 second sleep then I risk getting back all zero/null again.

Below is the code for my most recent attempt. The data at first seems fine until I try adding up the PercentProcessorTime and very quickly get over 100. More will be added to it once I can properly poll the data, like an array sort/slice.

Code:
Option Explicit
Dim objWMIService, objRefresher
Dim strComputer,strList
Dim colProcesses,objProcess

strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
set colProcesses = objRefresher.AddEnum (objWMIService, "Win32_PerfFormattedData_PerfProc_Process").objectSet

objRefresher.Refresh
WScript.Sleep(1000)
objRefresher.Refresh

strList = "Name      Proc"
for each objProcess in colProcesses
    strList = strList & vbCr & objProcess.Name & "      " & objProcess.PercentProcessorTime
next

WScript.Echo strList
Google has been almost no help whatsoever. I've cobbled the above together from about 15 different sources.

I could desperately use some help in getting this to work.

I've got the same exact script created in perl+linux that takes all of 2 lines of code (could be just 1 line through the miracle of shit-wizardry), but I can't for the life of me figure out how to do this on VBScript+Windows.

An additional and related question...

I will need a top 10 memory script as well. Once the basics are figured out with Proc this shouldn't be a problem, but will the same PerfFormatted data work just fine for this or will I need another WMI Object?
 

Ken g6

Programming Moderator, Elite Member
Moderator
Dec 11, 1999
16,284
3,905
75
I well know VBScript doesn't have a sort routine. I once wrote insertion sort there - sorry don't know where and it's proprietary code anyway - and it's the worst "normal" language I've ever used. (Barring Turing tarpits.)

Sorry, I don't have much useful input to give. Except maybe, "Why don't you just use Task Manager?" At least for memory use?
 

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
Heh, Ken. Commiserating with me about how crappy VBScript is does actually help Telling my wife and non-programmer coworkers my woes just isn't very satisfying.

The goal is to provide a tool for our tier 1 support team to have a quick and easy way to investigate alerts for high CPU and/or Memory on various network devices and servers. Currently the process involves connecting to a VPN, looking up the credentials, RDPing into the server, launching task manager - A fairly lengthy process just to find out the top offenders and escalate to the appropriate admin group. Our monitoring software already has the credentials, so polling the data semi-automatically would cut down the response time immensely.

Unfortunately, the monitoring software doesn't support local calls to Perl unless you are using ActiveState Perl which my company doesn't want to pay for, so I'm stuck with VBScript. I tried telling the main engineer that the following would be the best way to go about this, but he didn't like the idea:

Code:
Option Explicit
run "perl some_script_that_actually_works.pl"
 

Ken g6

Programming Moderator, Elite Member
Moderator
Dec 11, 1999
16,284
3,905
75
Bob, this might be a blind alley, but...

1. I know you can launch Task Manager with VBScript.
2. It looks like it's possible to take a screenshot with VBScript. Note that 'WshShell.SendKeys "{PRTSC}"' does not work.

Given that, it might be possible to launch Task Manager, sort on the key required, take a screenshot (maybe of just Task Manager with alt-PrintScreen), save it somewhere, and send it back to you somehow, perhaps on a shared drive or something. Right?

Or it might not even work - that's the only site I've seen saying you can take a screenshot with VBScript. Even if it does work, if alt-PrintScreen doesn't work to narrow the screenshot to the one app it might be too invasive for some people. Or given that high CPU/memory loads are an issue this might take too long and time out or something. But it might be worth looking into anyway.
 

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
That is a pretty interesting concept, Ken. Not sure that it would work out for what we are trying to do though
 

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
Found out from someone else that deals with this stuff that the IDLE process returns "bad" data. It will show close to 100% for some reason. Unfortunately, I can't run any additional tests until Wednesday, but it looks like removing the idle process from the return values will get me where I want to be.
 

Markbnj

Elite Member <br>Moderator Emeritus
Moderator
Sep 16, 2005
15,682
13
81
www.markbetz.net
Found out from someone else that deals with this stuff that the IDLE process returns "bad" data. It will show close to 100% for some reason. Unfortunately, I can't run any additional tests until Wednesday, but it looks like removing the idle process from the return values will get me where I want to be.

That's not bad data. The idle process is where CPU resources go when no other program is using them. If you look at task manager you'll see that it does indeed hover around 100%, but will drop when another process uses CPU time.
 

Ken g6

Programming Moderator, Elite Member
Moderator
Dec 11, 1999
16,284
3,905
75
Just in case it hasn't occurred to you, I was thinking: The best sorting algorithm you could use here is probably selection sort, selecting the largest element each time, and stopping after 10. Simple, but still relatively fast.
 

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
That's not bad data. The idle process is where CPU resources go when no other program is using them. If you look at task manager you'll see that it does indeed hover around 100&#37;, but will drop when another process uses CPU time.

This is a bit different. Apparently when you pull the data using the WMI Object the Idle process basically adds up all the processes or something similar. So it will show 99-100% even when there are other processes that are using resources. From the way it was explained to me, the retrieved Idle data should be discarded and if idle process needs to be calculated then the other processes should be subtracted from 100 to get the correct value.

Like I said though, can't test until Wednesday, but based on what I was seeing with my tests this seems to be the solution to the issue.

@Ken, selection sort sounds like it will work. tbh I hadn't even started thinking about sorting yet and would have likely just resorted to a basic bubble sort lol.
 

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
Well, it looks like the Idle process is returning bad data. If I exclude Idle from the array then everything looks just about right.

Here is the finalized, and extremely ugly, code for anyone interested.

Code:
Option Explicit
Dim objWMIService, objRefresher
Dim strComputer, strList
Dim colProcesses, sliceProcesses()
Dim objProcess, tempProcess
Dim i, j, iPos, iMax, listLen

strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\"  _
                                & strComputer & "\root\cimv2")

Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
set colProcesses = objRefresher.AddEnum (objWMIService, _
                            "Win32_PerfFormattedData_PerfProc_Process").objectSet

objRefresher.Refresh
WScript.Sleep(1000)
objRefresher.Refresh

Redim Preserve sliceProcesses(0)
i = 0

'strip Idle, Total, and 0 values
for each objProcess in colProcesses
    if ((objProcess.PercentProcessorTime > 0) _
            and (not objProcess.name = "Idle") _
            and (not objProcess.Name = "_Total")) then
        Redim Preserve sliceProcesses(i)
        set sliceProcesses(i) = objProcess
        i = i+1
    end if
next

'Selection Sort, didn't feel like fighting with it to get a slice
for iPos = 0 to UBound(sliceProcesses)
    iMax = iPos
    
    for i = iPos+1 to UBound(sliceProcesses)
        
        if CInt(sliceProcesses(i).PercentProcessorTime) > _
                    CInt(sliceProcesses(iMax).PercentProcessorTime) then
            iMax = i
        end if
    next
    
    if (not iMax = iPos) then
        set tempProcess = sliceProcesses(iPos)
        set sliceProcesses(iPos) = sliceProcesses(iMax)
        set sliceProcesses(iMax) = tempProcess
    end if
next

if UBound(sliceProcesses) > 10 then listLen = 10 else listLen = UBound(sliceProcesses)

'Sad excuse for Array Slice
for i = 0 to listLen
        strList = strList + vbCR & sliceProcesses(i).Name & _
                "    " & sliceProcesses(i).PercentProcessorTime
next

WScript.echo strList

I swear to god if I find this crap on dailyWTF I'm going to poop lol. Its this clunky VBScript.

Just for a laugh here is a script in perl for Linux that returns the exact same thing:
Code:
print `ps -A -o pid,comm,pcpu | sort -r -k 3 | head -n 11`;

Of course... the only reason perl is involved at all is because of the software we're using, but omg is it a breath of fresh air compared to VBScript.
 

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
Thanks Wanna, I had come across some similar powershell examples and dug into it that way, unfortunately it won't work for us Was much more promising than VBScript and more akin to the perl script so it seemed like a great solution.
 

Ken g6

Programming Moderator, Elite Member
Moderator
Dec 11, 1999
16,284
3,905
75
Well, I felt like cleaning up your code. Seems to work better on my machine - vbCR doesn't make a newline for me; might need vbLF. Plus, if you get more than 10 processes running at once, it should be faster as it stops sorting at 10.

Code:
Option Explicit
Dim objWMIService, objRefresher
Dim strComputer, strList
Dim colProcesses, sliceProcesses()
Dim objProcess, tempProcess
Dim i, j, iPos, iMax, listLen

strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\"  _
                                & strComputer & "\root\cimv2")

Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
set colProcesses = objRefresher.AddEnum (objWMIService, _
                            "Win32_PerfFormattedData_PerfProc_Process").objectSet

objRefresher.Refresh
WScript.Sleep(1000)
objRefresher.Refresh

Redim Preserve sliceProcesses(0)
i = 0

'strip Idle, Total, and 0 values
for each objProcess in colProcesses
    if ((objProcess.PercentProcessorTime > 0) _
            and (not objProcess.name = "Idle") _
            and (not objProcess.Name = "_Total")) then
        Redim Preserve sliceProcesses(i)
        set sliceProcesses(i) = objProcess
        i = i+1
    end if
next

'Selection Sort, did feel like fighting with it to get a slice
if UBound(sliceProcesses) > 10 then listLen = 10 else listLen = UBound(sliceProcesses)
for iPos = 0 to listLen
    iMax = iPos
    
    for i = iPos+1 to UBound(sliceProcesses)
        
        if CInt(sliceProcesses(i).PercentProcessorTime) > _
                    CInt(sliceProcesses(iMax).PercentProcessorTime) then
            iMax = i
        end if
    next
    
    if (not iMax = iPos) then
        set tempProcess = sliceProcesses(iPos)
        set sliceProcesses(iPos) = sliceProcesses(iMax)
        set sliceProcesses(iMax) = tempProcess
    end if
    WScript.echo sliceProcesses(iPos).Name & _
                "    " & sliceProcesses(iPos).PercentProcessorTime
next


And here's the fixed script in Perl for Linux that returns the exact same thing. Actually, the above code might print 11 processes, but whatever:
Code:
print `ps -A -o comm,pcpu | grep -v ' 0\\.0\$' | sort -r -k 2 | head -n 11 | tail`;
 

bobross419

Golden Member
Oct 25, 2007
1,981
1
0
Awesome, Ken!

Thanks for cleaning it up a bit for me. I found that to work with the monitoring software I actually had to use vbNewLine - vbCr, vbLf, etc. didn't get parsed as new lines by the software. Unfortunately, again because of the monitoring software, the WScript.Echo needs to be outside of the for loop and mashed into one long string *sigh*.

I really hate dealing with VBScript. I've told our manager that the next person they bring on needs to have VBScripting experience. We generally hire out of our help desk - I've suggested that on the next window I email the entire help desk this exact problem and the first 3 responses with valid scripts get interviewed. Unfortunately, I'm sure at least one of them will google and find this exact thread and give me my(our) own damn code lol.

As far as the pseudo-perl script goes... tim toady. PID on unix is nice for our sysadmins to easily kill processes, and I didn't pipe to tail because the extra header fields help readability. I'll probably add in the grep -v though to rip out processes that aren't consuming CPU resources though. Ripping out 0's was actually because I wanted to make the sort in VBScript less resource intensive and quicker lol.
 
sale-70-410-exam    | Exam-200-125-pdf    | we-sale-70-410-exam    | hot-sale-70-410-exam    | Latest-exam-700-603-Dumps    | Dumps-98-363-exams-date    | Certs-200-125-date    | Dumps-300-075-exams-date    | hot-sale-book-C8010-726-book    | Hot-Sale-200-310-Exam    | Exam-Description-200-310-dumps?    | hot-sale-book-200-125-book    | Latest-Updated-300-209-Exam    | Dumps-210-260-exams-date    | Download-200-125-Exam-PDF    | Exam-Description-300-101-dumps    | Certs-300-101-date    | Hot-Sale-300-075-Exam    | Latest-exam-200-125-Dumps    | Exam-Description-200-125-dumps    | Latest-Updated-300-075-Exam    | hot-sale-book-210-260-book    | Dumps-200-901-exams-date    | Certs-200-901-date    | Latest-exam-1Z0-062-Dumps    | Hot-Sale-1Z0-062-Exam    | Certs-CSSLP-date    | 100%-Pass-70-383-Exams    | Latest-JN0-360-real-exam-questions    | 100%-Pass-4A0-100-Real-Exam-Questions    | Dumps-300-135-exams-date    | Passed-200-105-Tech-Exams    | Latest-Updated-200-310-Exam    | Download-300-070-Exam-PDF    | Hot-Sale-JN0-360-Exam    | 100%-Pass-JN0-360-Exams    | 100%-Pass-JN0-360-Real-Exam-Questions    | Dumps-JN0-360-exams-date    | Exam-Description-1Z0-876-dumps    | Latest-exam-1Z0-876-Dumps    | Dumps-HPE0-Y53-exams-date    | 2017-Latest-HPE0-Y53-Exam    | 100%-Pass-HPE0-Y53-Real-Exam-Questions    | Pass-4A0-100-Exam    | Latest-4A0-100-Questions    | Dumps-98-365-exams-date    | 2017-Latest-98-365-Exam    | 100%-Pass-VCS-254-Exams    | 2017-Latest-VCS-273-Exam    | Dumps-200-355-exams-date    | 2017-Latest-300-320-Exam    | Pass-300-101-Exam    | 100%-Pass-300-115-Exams    |
http://www.portvapes.co.uk/    | http://www.portvapes.co.uk/    |