{"id":64923,"date":"2007-05-07T03:44:00","date_gmt":"2007-05-07T03:44:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/05\/07\/hey-scripting-guy-how-can-i-delete-all-the-duplicates-in-a-set-of-processes-but-keep-the-oldest-process\/"},"modified":"2007-05-07T03:44:00","modified_gmt":"2007-05-07T03:44:00","slug":"hey-scripting-guy-how-can-i-delete-all-the-duplicates-in-a-set-of-processes-but-keep-the-oldest-process","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-delete-all-the-duplicates-in-a-set-of-processes-but-keep-the-oldest-process\/","title":{"rendered":"Hey, Scripting Guy! How Can I Delete All the Duplicates in a Set of Processes But Keep the Oldest Process?"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> <\/H2>\n<P>Hey, Scripting Guy! If I have a bunch of duplicate processes, how can I delete all of them except for the oldest one?<BR><BR>&#8212; IR<\/P><IMG border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" border=\"0\" alt=\"Script Center\" align=\"right\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" height=\"288\"><\/A> \n<P>Hey, IR. We apologize for the delay in answering this question. Originally we thought it would be cute if we could get <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/sgwho.mspx\"><B>Peter Costantini<\/B><\/A>, the oldest living Scripting Guy, to answer this; after all, we figured Peter would get a kick out of a scenario in which everything except the <I>oldest<\/I> thing was targeted for elimination. And we <I>did<\/I> ask Peter if he knew how to do carry out this task, but instead of answering the question he began telling us stories about the Spanish-American War and the day he got his first Model T. After a half hour or so he insisted that we go to Denny\u2019s in time for the early-bird special; as soon as we got back to the office, he turned on <I>Wheel of Fortune<\/I> and fell asleep. When he woke up, he resumed telling us stories about the Spanish-American War. (Apparently he and Teddy Roosevelt were bitter rivals.)<\/P>\n<P>It was about that time when we decided we\u2019d better go ahead and answer this question ourselves:<\/P><PRE class=\"codeSample\">strComputer = &#8220;.&#8221;<\/p>\n<p>Set objWMIService = GetObject(&#8220;winmgmts:\\\\&#8221; &amp; strComputer &amp; &#8220;\\root\\cimv2&#8221;)<\/p>\n<p>Set colItems = objWMIService.ExecQuery _\n    (&#8220;Select * From Win32_Process Where Name = &#8216;Notepad.exe'&#8221;)<\/p>\n<p>If colItems.Count &lt; 2 Then\n    Wscript.Quit\nEnd If<\/p>\n<p>dtmTarget = Now<\/p>\n<p>For Each objItem in colItems\n    dtmDateHolder = objItem.CreationDate<\/p>\n<p>    dtmDateHolder = CDate(Mid(dtmDateHolder, 5, 2) &amp; &#8220;\/&#8221; &amp; _\n        Mid(dtmDateHolder, 7, 2) &amp; &#8220;\/&#8221; &amp; Left(dtmDateHolder, 4) _\n            &amp; &#8221; &#8221; &amp; Mid (dtmDateHolder, 9, 2) &amp; &#8220;:&#8221; &amp; _\n                Mid(dtmDateHolder, 11, 2) &amp; &#8220;:&#8221; &amp; Mid(dtmDateHolder, 13, 2))<\/p>\n<p>    If dtmDateHolder &lt; dtmTarget Then\n         intProcessID = objItem.ProcessID\n         dtmTarget = dtmDateHolder\n    End If\nNext<\/p>\n<p>Set colItems = objWMIService.ExecQuery _\n    (&#8220;Select * From Win32_Process Where Name = &#8216;Notepad.exe&#8217; &#8221; &amp; _\n        &#8220;AND ProcessID &lt;&gt; &#8221; &amp; intProcessID)<\/p>\n<p>For Each objItem in colItems\n    objItem.Terminate\nNext\n<\/PRE>\n<P>You say that it\u2019s a bit complicated looking? Well, yeah, a little. But don\u2019t worry; we\u2019ll explain how it all works, step-by-step.<\/P>\n<TABLE id=\"EOD\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. Peter would like us to inform everyone that back in <I>his<\/I> day he didn\u2019t need fancy stuff like Windows and Notepad just to terminate a few processes. Give him a punch card and the good old Univac I and in a few days he\u2019d get rid of those pesky old processes. And he\u2019d do it after walking 10 miles through waist-deep snow just to get to the office in the first place.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>As you can see, our script starts out in pretty straightforward fashion, binding to the WMI service on the local computer. (Although this script works equally well against remote machines; all you have to do is assign the name of the remote computer to the variable strComputer.) For this example, we\u2019ve decided that we want to get rid of any \u201cextra\u201d copies of Notepad that might be running. With that in mind, we go ahead execute this query to get back a collection of all the processes that have a <B>Name<\/B> equal to <I>Notepad.exe<\/I>:<\/P><PRE class=\"codeSample\">Set colItems = objWMIService.ExecQuery _\n    (&#8220;Select * From Win32_Process Where Name = &#8216;Notepad.exe'&#8221;)\n<\/PRE>\n<P>At this point we take a minor detour. Suppose it turns out that we have only one instance of Notepad running; in other words, suppose we don\u2019t have any duplicate processes running after all. If that\u2019s the case we\u2019re assuming that we don\u2019t want to terminate our one and only instance of Notepad. That\u2019s why we stuck in this block of code:<\/P><PRE class=\"codeSample\">If colItems.Count &lt; 2 Then\n    Wscript.Quit\nEnd If\n<\/PRE>\n<P>What we\u2019re doing here is checking the value of the <B>Count<\/B> property to see how many instances of Notepad really <I>are<\/I> up and running. If the Count is less than 2 that means we have, at most, one instance of Notepad running. In that case our work is done: there aren\u2019t any duplicate processes to be terminated. Therefore, we go ahead and call the <B>Wscript.Quit<\/B> method and terminate the script.<\/P>\n<P>Let\u2019s assume, however, that we <I>do<\/I> have multiple instances of Notepad running. In that case we need to figure out which instance is the oldest (that is, which instance was created first), then go ahead and delete all the other instances of Notepad. There are a number of different ways to do this, but we chose the following approach.<\/P>\n<P>The first thing we do is assign the current date and time (using the <B>Now<\/B> function) to a variable named dtmTarget. Why? Well, we\u2019re going to check the creation date and time of each instance of Notepad against this target date and time. Suppose we check the creation time for Notepad instance 1 and find out that it\u2019s older than the value in dtmTarget (which it will be). In that case, Notepad instance 1 becomes our oldest instance of Notepad, and we\u2019ll assign <I>its<\/I> creation date and time to dtmTarget. We\u2019ll then check the creation date and time of Notepad instance 2 against the new value of dtmTarget. What if Notepad instance 2 is \u201cyounger\u201d than dtmTarget? No problem; in that case we just loop around and repeat the process with Notepad instance 3. <\/P>\n<P>If it turns out that Notepad instance 2 is older than dtmTarget then we assign its creation date and time to dtmTarget. That means that, for the moment at least, Notepad instance 2 is our oldest instance.<\/P>\n<P>Make sense? If not, bear with us; we\u2019ll show you exactly how this all takes place.<\/P>\n<P>After retrieving all the instances of Notepad we set up a For Each loop to walk through each item in the collection. The first thing we do inside that loop is assign the value of the process CreationDate property to a variable named dtmDateHolder:<\/P><PRE class=\"codeSample\">dtmDateHolder = objItem.CreationDate\n<\/PRE>\n<P>This is where things get a little messy. The value of the CreationDate property \u2013 like most WMI date-time values \u2013 is stored using the Universal Time Coordinate (UTC) format; that means that dtmDateHolder is going to be equal to something like this:<\/P><PRE class=\"codeSample\">20070504085221.620161-420\n<\/PRE>\n<P>Needless to say, there\u2019s not a lot we can do with a UTC value, at least not in that particular format. Instead, we need to convert this to a \u201creal\u201d date-time value. That\u2019s what this block of code is for:<\/P><PRE class=\"codeSample\">dtmDateHolder = CDate(Mid(dtmDateHolder, 5, 2) &amp; &#8220;\/&#8221; &amp; _\n    Mid(dtmDateHolder, 7, 2) &amp; &#8220;\/&#8221; &amp; Left(dtmDateHolder, 4) _\n        &amp; &#8221; &#8221; &amp; Mid (dtmDateHolder, 9, 2) &amp; &#8220;:&#8221; &amp; _\n            Mid(dtmDateHolder, 11, 2) &amp; &#8220;:&#8221; &amp; Mid(dtmDateHolder, 13, 2))\n<\/PRE>\n<P>We won\u2019t discuss the ins and outs of converting a UTC value to a regular date-time value; for detailed information on that take a look at the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/guide\/sas_wmi_yakv.mspx\" target=\"_blank\"><B>Microsoft Windows 2000 Scripting Guide<\/B><\/A>. About all we <I>will<\/I> say is that the preceding block of code turns a value like 20070504085221.620161-420 into a value like this:<\/P><PRE class=\"codeSample\">5\/4\/2007 8:52:21 AM\n<\/PRE>\n<P>Obviously that\u2019s a value that is much easier for us to work with. More important, it\u2019s a value that\u2019s much easier for VBScript to work with.<\/P>\n<P>OK. Let\u2019s next assume that the value of dtmTarget is equal to this:<\/P><PRE class=\"codeSample\">5\/4\/2007 8:58:13 AM\n<\/PRE>\n<P>In our next line of code we check to see if our first process (dtmDateHolder) is older than this target date:<\/P><PRE class=\"codeSample\">If dtmHolder &lt; dtmTarget Then\n<\/PRE>\n<P>In this case, of course, that\u2019s going to be true: our process <I>is<\/I> older than the target date. Therefore we do two things: 1) we assign the value of the <B>ProcessID<\/B> property to a variable named intProcessID, and 2) we assign the value of dtmDateHolder to our target variable (dtmTarget). That\u2019s what these two lines of code are for:<\/P><PRE class=\"codeSample\">intProcessID = objItem.ProcessID\ndtmTarget = dtmDateHolder\n<\/PRE>\n<P>What\u2019s the point of all that? Well, now we know the creation date and time for the oldest process (or at least the oldest process so far). In addition, we also know the process ID for the oldest process. That\u2019s important, because when it comes time to start deleting processes we need an easy way to ensure that we don\u2019t delete the oldest process. Because process IDs are unique this seemed like a pretty good way to separate the oldest process from the rest of the herd.<\/P>\n<P>We then loop around and do this all over again with the next item in the collection. When we\u2019ve finished looping through the entire collection the variable intProcessID will contain the process ID for the oldest instance of Notepad running on the computer.<\/P>\n<P>Still with us? Good. We\u2019re almost done. Promise.<\/P>\n<P>It\u2019s now time to get rid of all those young whippersnapper instances of Notepad. How are we going to do that? To begin with, we\u2019re going to retrieve a brand-new collection of processes, using the following query:<\/P><PRE class=\"codeSample\">Set colItems = objWMIService.ExecQuery _\n    (&#8220;Select * From Win32_Process Where Name = &#8216;Notepad.exe&#8217; &#8221; &amp; _\n        &#8220;AND ProcessID &lt;&gt; &#8221; &amp; intProcessID)\n<\/PRE>\n<P>With this query we\u2019re still retrieving all the members of the Win32_Process class that have a Name equal to <I>Notepad.exe<\/I>. However, we\u2019ve now added a second stipulation: we only want those instances of Notepad where the ProcessID is <I>not<\/I> equal to intProcessID. That\u2019s what this clause is for:<\/P><PRE class=\"codeSample\">AND ProcessID &lt;&gt; &#8221; &amp; intProcessID\n<\/PRE>\n<P>What will that do? That will retrieve all the instances of Notepad <I>except for<\/I> the instance that has a process ID equal to intProcessID. And because intProcessID just happens to have the same process ID as our oldest instance of Notepad that means that our collection will contain all the instances of Notepad except for the oldest one. <\/P>\n<P>That also means that we can now delete all the instances of Notepad (except, of course, for the oldest instance) by using this little block of code:<\/P><PRE class=\"codeSample\">For Each objItem in colItems\n    objItem.Terminate\nNext\n<\/PRE>\n<P>And there you have it. If only Peter were still alive to see this.<\/P>\n<TABLE id=\"EXG\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. Peter has just informed us that he <I>is<\/I> still alive. We believe him. However, we\u2019d still like to get a second opinion.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Incidentally, a lot of people ask us just how old Peter really is. As we noted in one of our webcasts, he\u2019s only 27; he\u2019s actually old only in comparison to the other Scripting Guys, all of whom are barely out of their teens.<\/P>\n<TABLE id=\"EGH\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. What\u2019s that? If the other Scripting Guys are barely out of their teens then how could the Scripting Son be 17 years old? You know, that\u2019s a really good question, and we\u2019d love to answer it. However, it\u2019s time for the early-bird special at Denny\u2019s. See you tomorrow!<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! If I have a bunch of duplicate processes, how can I delete all of them except for the oldest one?&#8212; IR Hey, IR. We apologize for the delay in answering this question. Originally we thought it would be cute if we could get Peter Costantini, the oldest living Scripting Guy, to answer [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[31,87,3,5],"class_list":["post-64923","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-operating-system","tag-processes","tag-scripting-guy","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! If I have a bunch of duplicate processes, how can I delete all of them except for the oldest one?&#8212; IR Hey, IR. We apologize for the delay in answering this question. Originally we thought it would be cute if we could get Peter Costantini, the oldest living Scripting Guy, to answer [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64923","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=64923"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64923\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=64923"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=64923"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=64923"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}