Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I determine which account a script is running under?

-- KW

SpacerHey, Scripting Guy! AnswerScript Center

Hey, KW. You know, it’s been awhile since we started off a column with a bunch of excuses, and that’s been hard on us: after all, making excuses is what we Scripting Guys do best. With that in mind, then, let’s start off with one of our favorite excuses: the script we’re about to show you works only on Windows XP and Windows Server 2003. We’ll show you a way to kind of, sort of do this same thing on Windows 2000, but it’s definitely not as good.

Ah, yes: now that felt good.

OK, no more excuses (for now, at least). Instead, let’s talk scripting. Here’s what the script looks like:

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

Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where " & _
    "Name = 'cscript.exe' or Name = 'wscript.exe'")

For Each objProcess in colProcessList
    If InStr(objProcess.CommandLine, "test.vbs") Then
        colProperties =   objProcess.GetOwner(strNameOfUser,strUserDomain)
        Wscript.Echo "This script is running under the account belonging to " _ 
            & strUserDomain & "\" & strNameOfUser & "."
    End If
Next

As you can see, we begin by connecting to the WMI service on the local computer, although this same script could just as easily be targeted against a remote machine. (Yes, we do say that a lot. But that isn’t an excuse, it’s just a statement of fact: almost all WMI scripts work equally well against a remote computer as they do the local computer. Every now and then we do say something that isn’t an excuse!)

We then encounter this line of code:

Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where " & _
    "Name = 'cscript.exe' or Name = 'wscript.exe'")

You might have already guessed that we need to use the Win32_Process class to carry out our task; that’s because Win32_Process is the WMI class that keeps track of all the processes currently running on a computer. Of course, we aren’t interested in all the processes running on the computer; we’re only interested in the scripts. Because of that we include a Where clause that restricts the returned information only to instances of the two Windows script hosts: Cscript.exe and Wscript.exe.

Note. Yes, we could have written this script in a slightly different fashion, and maybe saved a line or two of code in the process. We opted for this approach because it more closely resembles the way we have to do this chore on Windows 2000.

After issuing the query we set up a For Each loop to walk through the returned collection. In this example we’re trying to determine the owner for a script named Test.vbs. Therefore, we need to check each script to see if it happens to be named Test.vbs. How do we do that? By using this line of code:

If InStr(objProcess.CommandLine, "test.vbs") Then

All we’re doing here is using the InStr function to see if the string test.vbs can be found anywhere in the CommandLine property. And what is the CommandLine property? In somewhat simplistic fashion, this is the command string required to start the script from a command prompt. For example, the CommandLine might be something like this:

C:\Scripts\Test Scripts\Test.vbs

We’re checking for test.vbs because we’re assuming we don’t have a script named, say, MyTest.vbs. If you’re concerned with this kind of name collision, then we could simply use InStr and test for a string like \test.vbs. That’s something you’ll have to decide for yourself.

If it turns out that our target string can be found in the CommandLine value we then call the GetOwner method to find out the “owner” of the process (that is, the name of the account that the script is running under):

objProcess.GetOwner(strNameOfUser,strUserDomain)

With GetOwner, we need to pass along a pair of “out parameters.” An out parameter is nothing more than a variable (which we name ourselves) that the method will fill with a value. Here we’re passing variables named strNameOfUser and strUserDomain; in return, GetOwner will assign those variables the name of the user and the domain of the user who owns the process.

At that point all we have to do is echo back the returned information:

Wscript.Echo "This script is running under the account belonging to " _ 
    & strUserDomain & "\" & strNameOfUser & "."

So then why can’t we run this same script on Windows 2000? Actually there’s a good reason for that: the CommandLine property is found only on Windows XP and Windows Server 2003. On other versions of Windows we can’t identify individual scripts; the best we can do is return owner information for any instances of Cscript.exe and Wscript.exe that happen to be running. If there’s only one script running, no problem: that single instance of CScript.exe or Wscript.exe has to represent that one script. In turn, that means the owner of the script host process is also the owner of the script process. If you have multiple scripts running, though, that’s a different story. If that’s the case, the best you can do is say, “Well, Ken Myer owns one of these scripts, although we don’t know which one. And whichever one he doesn’t own Pilar Ackerman does own.”

No, not quite as good. But it is what it is. (And yes, that is an excuse. A somewhat lame one, but an excuse nonetheless.)

Here’s what the Windows 2000 solution (OK: semi-solution) looks like:

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

Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where " & _
    "Name = 'cscript.exe' or Name = 'wscript.exe'")

For Each objProcess in colProcessList
    objProcess.GetOwner strNameOfUser,strUserDomain
    Wscript.Echo "A script is running under the account belonging to " _ 
        & strUserDomain & "\" & strNameOfUser & "."
Next