Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I get the process ID for a file like MyExecutableFile.exe, but only if a certain user is the owner of that process?

-- SC

SpacerHey, Scripting Guy! AnswerScript Center

Hey, SC. You know, here at Microsoft ownership is very important; for example, when you sit down to discuss joint projects with people the very first question that comes up is this: who actually owns this project?

Is that because people at Microsoft want to own everything? Heavens no: after all, the owner of the project has to do all the implementation and all the maintenance, has to respond to customer feedback, has to fix bugs, etc. No one wants to own everything; on the contrary, people are always working to ensure that they don’t own anything. If you’re really clever you can figure out a way to get credit for stuff without actually having to own that stuff. That’s what the smart people around here do all the time.

Which, alas, explains why the Scripting Guys own the Script Center and everything in it.

Note. Sure, maybe we’re a little naïve and gullible at times. But once we get our hands on that $90 million we are helping the widow of the Nigerian Defense Minister transfer to a US bank account, well, then we’ll see who has the last laugh.

So can we get the process ID for an executable file, but only if that file is owned by a specific user? Of course we can:

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process Where Name = 'notepad.exe'")

For Each objProcess in colProcessList
    objProcess.GetOwner strNameOfUser,strUserDomain
    strOwner = strUserDomain & "\" & strNameOfUser
    If LCase(strOwner) = "fabrikam\kenmyer" Then
        Wscript.Echo objProcess.Handle
    End If
Next

Yes, it’s that easy. What we’re doing here is getting the process ID for any instance of Notepad that is owned by the account fabrikam\kenmyer. To do that, we begin by connecting to the WMI service on the local computer (although we could just as easily run this script against a remote computer). We then use the ExecQuery method to retrieve a collection of all the processes that have a Name equal to notepad.exe:

Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process Where Name = 'notepad.exe'")

Good question: wouldn’t it be better if we ran a query that returned all the processes that had a Name equal to notepad.exe and an owner equal to fabrikam\kenmyer? You bet it would; unfortunately, though, we can’t do that. That’s because the name of the process owner can’t be retrieved as part of a query; instead, we have to use the GetOwner method to individually retrieve process owners one-by-one. In fact, there’s really only one reason that we even bother to limit the returned data to processes with the Name notepad.exe: that way we’ll have fewer processes we need to run GetOwner against.

Speaking of which, as soon as we have our collection we set up a For Each loop to cycle through each process in the collection; the very first thing we do inside that loop is call the GetOwner method:

objProcess.GetOwner strNameOfUser,strUserDomain

As you can see, for the process in question we call GetOwner and include a pair of “out” parameters: strNameOfUser and strUserDomain. Out parameters are nothing more than variables, and the names are arbitrary: we can name these variables anything we want. (We chose strNameOfUser and strUserDomain because the names just seem to roll off the tongue, don’t they?) The only real difference between out parameters and regular old variables is that we never assign a value to these parameters; instead, the GetOwner method assigns the name and domain of the process owner to strNameOfUser and strUserDomain, respectively.

Once that’s done we then use this line of code to construct an owner name using the format domain\user (e.g., fabrikam\kenmyer):

strOwner = strUserDomain & "\" & strNameOfUser

At this point we finally know the owner of the process; the only thing we don’t know is whether or not this happens to be the user we’re interested in. To answer that question we use the following If statement to determine whether the lowercase value of strOwner (the variable containing the owner name) is equal to fabrikam\kenmyer:

If LCase(strOwner) = "fabrikam\kenmyer" Then

If the owner is fabrikam\kenmyer we echo back the process ID (which can be found in the Handle property). If the owner happens to be anyone else, well, then we don’t do anything at all. Which is what we Scripting Guys do best.

Does that answer your question, SC? If not, please don’t write to us; instead, we ask you to direct all additional inquiries to the owner of this particular column.

Which would be, well, us. You know, we really have to work on taking credit for stuff without actually owning it, don’t we?