Real-Life Scripting With Microsoft Office
Build Your Own Task Manager Using Microsoft Word (No, Really)
When you bought your copy of Microsoft Office, you probably knew that you were getting a world-class set of applications, everything from a spreadsheet to a word-processor to an email client. What you might not have known is that you were also getting the answer to a question that has vexed script writers for years: how can I retrieve a list of all the applications and open windows running on a computer?
Now, keep in mind we’re not talking about getting a list of all the processes running on a computer; if you want that data you can use WMI’s Win32_Process class. If we ask Win32_Process to retrieve the names of all the processes running on a computer we’ll get back information similar to this:
There’s nothing wrong with this information; in fact you will often want a complete set of all the processes running on a computer. At other times, though, you just want the list of items found on the Applications tab in Task Manager:
In other words, you want just the open windows, and you’d like to get back the friendly names as opposed to executable files names (such as Portable Script Center rather than hh.exe). But WMI won’t let you get to this information, and neither will any other scripting object built into the operating system. (The Shell object provides a way to list all the shell items open on a computer, but that’s about it.)
Amazingly enough, however, Microsoft Office can get this information for you. The Microsoft Word Application object includes a Tasks property that returns a collection of all the processes running on a computer. One difference between this and Win32_Process is the fact that the Tasks collection returns friendly names for these processes rather than executable file names. Thus you get back information that looks like this:
But wait: there’s at least one other difference between the Task objects which represent the individual processes in the Tasks collection and the objects returned by Win32_Process. As we wrote this article, we had 46 processes running on the computer; however, only 11 items showed up on the Applications tab in Task Manager. That’s because most of these processes – including most services – run in a hidden window. This is how Task Manager determines the processes that appear on the Applications tab. If you can see the window in which the process is running, then it shows up as an application. If you can’t see the window, then it doesn’t show up as an application.
Note. We’ll show you a script later on that returns the friendly names for all the processes running on your computer. It’s difficult to look at executable file names and have any idea what’s actually running on your machine; the friendly names give you a much clearer picture.
Win32_Process has no way of knowing whether a process is running in a hidden window or not; because of that it can’t identify the processes that Task Manager marks as applications. The Task object, however, includes a property – Visible – that indicates whether or not the process is running in a visible window. We can take advantage of the Visible property to identify open windows and applications.
In fact, let’s take a look at a script that does this very thing:
Set objWord = CreateObject("Word.Application") Set colTasks = objWord.Tasks For Each objTask in colTasks If objTask.Visible Then Wscript.Echo objTask.Name End If Next objWord.Quit
We begin by creating an instance of Microsoft Word. After stashing the Tasks collection in a variable named colTasks we set up a For Each loop to walk through the collection. For each individual task (that is, for each process running on the computer) we check to see if the process is running in a visible window. That’s what this line of code does:
If objTask.Visible Then
If the Visible property is True, we echo the Name of the task. If the Visible property is False (meaning the process is running in a hidden window), we simply loop around and examine the next task in the collection. After we’ve run through the entire collection we quit Word, and the script ends.
And what’s the net result? Well, the net result is that we get back a list almost identical to the list found on the Applications tab in Task Manager. The only difference is that Program Manager – which, beginning with Windows 98, actually refers to the Start menu – appears in our scripted output, but does not appear in Task Manager. Along similar lines, Task Manager itself does not appear on the Applications tab in Task Manager, although it will appear in our scripted output.
Is that cool or what? If we wanted to get back a list of all the processes, regardless of whether they are visible or not, we can use a script like this:
Set objWord = CreateObject("Word.Application") Set colTasks = objWord.Tasks For Each objTask in colTasks Wscript.Echo objTask.Name Next objWord.Quit
But that’s not even the half of it. Want to know if someone is playing Solitaire on a computer? Then use the Exists method to see if Solitaire appears in the Tasks collection:
Set objWord = CreateObject("Word.Application") Set colTasks = objWord.Tasks If colTasks.Exists("Solitaire") Then Wscript.Echo "Someone is playing Solitaire." End If objWord.Quit
And if you’d prefer that they not play Solitaire, well, then use the Close method to shut Solitaire down:
Set objWord = CreateObject("Word.Application") Set colTasks = objWord.Tasks If colTasks.Exists("Solitaire") Then colTasks("Solitaire").Close End If objWord.Quit
Alternatively, you could help the person out by bringing Solitaire to the front and maximizing it. That can be done by first activating the window (using the Activate method) and then setting the WindowState property to wdWindowStateMaximize (a constant we define and assign the value 1). For example:
Const wdWindowStateMaximize = 1 Set objWord = CreateObject("Word.Application") Set colTasks = objWord.Tasks If colTasks.Exists("Solitaire") Then colTasks("Solitaire").Activate colTasks("Solitaire").WindowState = wdWindowStateMaximize End If objWord.Quit
If you’d rather minimize the window, then assign the constant wdWindowStateMaximize a value of 2.
While you’re at it, the Task object also lets you get at a few other window properties, including Height, Width, Top (the vertical position of the window, measured in points), and Left (the horizontal position of the window, measured in points). Thus you could write a script similar to this:
Set objWord = CreateObject("Word.Application") Set colTasks = objWord.Tasks If colTasks.Exists("Solitaire") Then Wscript.Echo "Name: " & colTasks("Solitaire").Name Wscript.Echo "Top: " & colTasks("Solitaire").Top Wscript.Echo "Left: " & colTasks("Solitaire").Left Wscript.Echo "Height: " & colTasks("Solitaire").Height Wscript.Echo "Width: " & colTasks("Solitaire").Width End If objWord.Quit
Which returns data similar to this:
Name: Solitaire Top: 65 Left: 50 Height: 329 Width: 445
And all this time you thought Word was just for writing memos. Hey, when Microsoft says Word can do everything, we really mean it!
Of course, we should point out that the Tasks collection in Word can complement the Win32_Process class, but it definitely doesn’t take the place of Win32_Process. That’s because Win32_Process returns a ton of information – kernel mode time, user mode time, process ID, handle count – that the Tasks collection can’t return. In addition, we don’t see an obvious way to tie a program retrieved by the Tasks collection to its corresponding process in Win32_Process. If and when we do, we’ll let you know.