Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I determine the date and time that a process started?

-- BM

SpacerHey, Scripting Guy! AnswerScript Center

Hey, BM. We’ve got good news for you: not only do we have an answer to your question, but we’re not going to bore everyone with any more stories regarding our Colt League All-Star team. Nope, we’re no longer haunted by the fact that, in a tie game, we had the bases loaded, one out, and were unable to score a run, even though we have our three and four hitters up. We are no longer wondering what might have happened had we been able to get that bunt down early in the game. What if our third baseman hadn’t lost that popup in the sun? Hey, it doesn’t matter; it’s just a game, right?

OK, we don’t believe that for a second. Therefore, maybe we better try to forget about baseball and answer your question for you. Here’s a script that can tell you the date and time that Notepad.exe started:

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
    Wscript.Echo objProcess.CreationDate
Next

Yes, very easy. We start off by binding to the WMI service, then use this query to return a collection of all the processes named notepad.exe:

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

We then set up a For Each loop to cycle through the collection, echoing the value of the CreationDate property for each item in the collection. How complicated could something like that be?

Well, OK, maybe a little more complicated than what we showed you. The preceding script works, but there is a problem. The CreationDate property, like most WMI date-time values, is stored using the Universal Time Coordinate (UTC) format. That means that the process start time is going to be returned looking something like this:

20050718095318.019149-420

How…nice….

We won’t go into all the gory details regarding the UTC time format; you can find a reasonably good discussion of that in the Microsoft Windows 2000 Scripting Guide. Although it might not look like it, our return value actually has all the information we need; for example, the 2005 at the beginning of the string indicates the year (2005), the subsequent 07 indicates the month (July), and so on. All we have to do is parse the string and put the pieces back together in a more-recognizable format.

One way to do that is to use the VBScript string manipulation functions to grab the individual date parts out of the return value and then rearrange them in a standard date-time format. (There’s actually an easier way to do this on Windows XP and Windows Server 2003, but we’ll show you a more generic approach for now.) For example, we know that characters 1 through 4 in our return value represent the year that the process started; therefore, we can use code like this to return just those four characters (assuming that we’ve stored the return value in a variable named dtmStart):

Left(dtmStart, 4)

As you can see, we use the Left function to grab the four leftmost characters (that is, the first four characters in the string). We also know that the month is represented by characters 5 and 6. Therefore we can use the Mid functions to grab the two characters that begin at position 5 in the string:

Mid(dtmStart, 5, 2)

Carried all the way out, we end up with a function similar to this:

Function WMIDateStringToDate(dtmStart)
    WMIDateStringToDate = CDate(Mid(dtmStart, 5, 2) & "/" & _
        Mid(dtmStart, 7, 2) & "/" & Left(dtmStart, 4) _
            & " " & Mid (dtmStart, 9, 2) & ":" & _
                Mid(dtmStart, 11, 2) & ":" & Mid(dtmStart, _
                    13, 2))
End Function

All we have to do now is incorporate this function into our script. To do that we don’t echo the value of the CreationDate property; instead, we store that value in a variable named dtmStartTime. We pass that value to our function, then echo the revised value returned by that function. Here’s what our modified For Each loop looks like:

For Each objProcess in colProcessList
    dtmStartTime = objProcess.CreationDate
    strReturn = WMIDateStringToDate(dtmStartTime)
    Wscript.Echo strReturn 
Next

And here’s what the new and improved script looks like:

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
    dtmStartTime = objProcess.CreationDate
    strReturn = WMIDateStringToDate(dtmStartTime)
    Wscript.Echo strReturn 
Next

Function WMIDateStringToDate(dtmStart)
    WMIDateStringToDate = CDate(Mid(dtmStart, 5, 2) & "/" & _
        Mid(dtmStart, 7, 2) & "/" & Left(dtmStart, 4) _
            & " " & Mid (dtmStart, 9, 2) & ":" & _
                Mid(dtmStart, 11, 2) & ":" & Mid(dtmStart, _
                    13, 2))
End Function

When we run this script we get back output that looks like this:

7/18/2005 9:53:18 AM

That’s a little nicer, almost nice enough to make you wonder what would have happened had we changed pitchers one batter earlier, right before we gave up that bases-loaded triple….