{"id":64953,"date":"2007-05-02T21:45:00","date_gmt":"2007-05-02T21:45:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/05\/02\/how-can-i-ensure-that-a-script-runs-only-once-on-a-computer\/"},"modified":"2007-05-02T21:45:00","modified_gmt":"2007-05-02T21:45:00","slug":"how-can-i-ensure-that-a-script-runs-only-once-on-a-computer","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-ensure-that-a-script-runs-only-once-on-a-computer\/","title":{"rendered":"How Can I Ensure That a Script Runs Only Once on a Computer?"},"content":{"rendered":"<p><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> \n<P>Hey, Scripting Guy! How can I ensure that a script runs only once on a computer?<BR><BR>&#8212; ML<\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\"><\/A> \n<P>Hey, ML. You know, we were going to start off today\u2019s column by saying, \u201cShow us your bobbleheads!\u201d However, we didn\u2019t want to have to explain to Microsoft people that there was nothing risqu\u00e9 or offensive in that statement; instead, all we wanted is to see what people have done with their Dr. Scripto Bobblehead dolls. (Hard as this is to believe, not everyone who works at Microsoft is a fun-loving, carefree type who enjoys a good laugh every now and then.) So while we <I>do<\/I> want people to show us their bobbleheads, we\u2019re not going to ask people to show us their bobbleheads. After all, the last thing the Scripting Guys want to do is get themselves into trouble.<\/P>\n<P>In other words, whatever you do, <I>don\u2019t<\/I> show us your bobbleheads. Thank you.<\/P>\n<P>Instead, if you were one of the lucky 250 people who won a bobblehead during the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/default.mspx\"><B>2007 Winter Scripting Games<\/B><\/A> we\u2019d love to know what you\u2019ve done with it. Just snap a digital photo and send it to <A href=\"mailto:scripter@microsoft.com\"><B>scripter@microsoft.com (in English, if possible)<\/B><\/A>. We\u2019ll <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/bobbles.mspx\"><B>publish your photo<\/B><\/A> in the Script Center, right alongside the cool picture we received from Switzerland\u2019s very own Ben Simkins:<\/P><IMG height=\"248\" alt=\"Spacer\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/bobble\/switzerland1.jpg\" width=\"330\" border=\"0\"> \n<P>&nbsp;<\/P>\n<TABLE class=\"dataTable\" id=\"E3D\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. Yes, that <I>is<\/I> Dr. Scripto. How are you supposed to tell the difference between Dr. Scripto and Scripting Guy Jean Ross? Here\u2019s a hint: Dr. Scripto doesn\u2019t have any <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/mms2007\/tuesday.mspx\"><B>staples in his head<\/B><\/A>.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>OK, let\u2019s get down to business. To tell you the truth, we don\u2019t know of a foolproof way to ensure that a script runs only once on a computer; there might very well <I>be<\/I> such a way, but it\u2019s probably too complicated to configure and even more complicated to enforce. Therefore, we\u2019ve come up with a simpler solution, one that might not be 100% foolproof, but at least is easy to implement.<\/P>\n<P>What we\u2019re going to do is this: each time the script in question runs, the first thing it\u2019s going to do is check a value in the registry. If that value is <I>No<\/I> that means the script has never run on this computer. As a result, the script will go ahead and run, and then, upon completion, change the registry value to <I>Yes<\/I>. Logically enough, if the registry value is <I>Yes<\/I> that means that script <I>has<\/I> run on the computer. So what happens if you try to run the script a second time? That\u2019s easy: the script checks the registry, sees that it has already run, and then automatically terminates itself. Not the fanciest approach in the world, but it should work.<\/P>\n<P>Of course, before we can actually <I>get<\/I> the script to work we need to create a registry value. To accomplish that task we need to do two things. First, we need to create a new registry key (in the HKEY_LOCAL_MACHINE hive) named <I>AdminScripts<\/I>. Once that\u2019s done we\u2019ll then need to create a new registry value named <I>Script 1<\/I> inside the AdminScripts key. Here\u2019s what the script that accomplishes both of those tasks looks like:<\/P><PRE class=\"codeSample\">Const HKEY_LOCAL_MACHINE = &amp;H80000002<\/p>\n<p>strComputer = &#8220;.&#8221;<\/p>\n<p>Set objRegistry = GetObject(&#8220;winmgmts:\\\\&#8221; &amp; strComputer &amp; &#8220;\\root\\default:StdRegProv&#8221;)<\/p>\n<p>strKeyPath = &#8220;SOFTWARE\\AdminScripts&#8221;\nobjRegistry.CreateKey HKEY_LOCAL_MACHINE, strKeyPath<\/p>\n<p>strValueName = &#8220;Script 1&#8221;\nstrValue = &#8220;No&#8221;\nobjRegistry.SetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue\n<\/PRE>\n<TABLE class=\"dataTable\" id=\"EPF\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note:<\/B> If you run this script on Windows Vista, you need to open the command prompt window as an administrator. Right-click Command Prompt in the Start menu and select Run As Administrator. We remind you of this because if you don\u2019t Run As Administrator, the script will run just fine with no errors. This seems fine, until you discover that you don\u2019t have a new registry key.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>As you can see, we start out by defining a constant named HKEY_LOCAL_MACHINE and setting the value to &amp;H80000002; this constant tells the script which registry hive we want to work with. We then connect to the WMI service on the local computer, binding directly to the <B>StdRegProv<\/B> class, which just happens to live in the <B>root\\default<\/B> namespace:<\/P><PRE class=\"codeSample\">Set objRegistry = GetObject(&#8220;winmgmts:\\\\&#8221; &amp; strComputer &amp; &#8220;\\root\\default:StdRegProv&#8221;)\n<\/PRE>\n<P>And sure, you can run this script against a remote computer; just assign the name of that remote computer to the variable strComputer. For example, this line of code causes the script to run against the remote machine atl-fs-01:<\/P><PRE class=\"codeSample\">strComputer = &#8220;atl-fs-01&#8221;\n<\/PRE>\n<P>Once we\u2019ve gotten this far, creating the new registry key is a piece of cake: all we have to do is assign the registry path to a variable named strKeyPath and then call the <B>CreateKey<\/B> method. That\u2019s what we do with these two lines of code:<\/P><PRE class=\"codeSample\">strKeyPath = &#8220;SOFTWARE\\AdminScripts&#8221;\nobjRegistry.CreateKey HKEY_LOCAL_MACHINE, strKeyPath\n<\/PRE>\n<P>As soon as the registry key exists we can then add a new value to that key. To do that we first assign the value name to a variable named strValueName; after that we assign the default value (No) to a variable named strValue. That\u2019s what these two lines of code are for:<\/P><PRE class=\"codeSample\">strValueName = &#8220;Script 1&#8221;\nstrValue = &#8220;No&#8221;\n<\/PRE>\n<P>And then we simply call the <B>SetStringValue<\/B> method, which not only creates the <I>Script 1<\/I> registry value but \u2013 as an added bonus \u2013 assigns it the value No to boot:<\/P><PRE class=\"codeSample\">objRegistry.SetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue\n<\/PRE>\n<P>That was easy, wasn\u2019t it? We might add that we opted to approach today\u2019s problem by splitting the task into two parts: first we created the registry key and value (that\u2019s the part we just showed you), then we created (or, to be more accurate, are about to create) a second script, the script that we want to run only once per computer. Could we have combined these two scripts into a single script, one that checks for the presence of the registry value and, if it doesn\u2019t exist, goes ahead and creates it? Sure. For information on verifying whether or not a registry value exists see <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/oct04\/hey1029.mspx\"><B>this column<\/B><\/A> from our oldies-but-goodies section.<\/P>\n<TABLE class=\"dataTable\" id=\"E5G\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. Why didn\u2019t we just combine these two scripts in the first place? Mainly because we wanted to keep things simple: in our experience, it\u2019s typically easier for people to read and understand two 10-line scripts than it is to read and understand one 20-line script. And trust us, when it comes to being simple no one is simpler than the Scripting Guys.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>So what <I>about<\/I> that other script, the one we want to run only once on a computer? Well, here\u2019s a quick-and-easy version that demonstrates the concept:<\/P><PRE class=\"codeSample\">Const HKEY_LOCAL_MACHINE = &amp;H80000002<\/p>\n<p>strComputer = &#8220;.&#8221;<\/p>\n<p>Set objRegistry = GetObject(&#8220;winmgmts:\\\\&#8221; &amp; strComputer &amp; &#8220;\\root\\default:StdRegProv&#8221;)<\/p>\n<p>strKeyPath = &#8220;SOFTWARE\\AdminScripts&#8221;\nstrValueName = &#8220;Script 1&#8221;\nobjRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue<\/p>\n<p>If strValue = &#8220;No&#8221; Then\n    Wscript.Echo &#8220;This script will now run.&#8221;\n    strValue = &#8220;Yes&#8221;\n    objRegistry.SetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue\nElse\n    Wscript.Quit\nEnd If\n<\/PRE>\n<TABLE class=\"dataTable\" id=\"EPH\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note:<\/B> Same thing here about Windows Vista: Run As Administrator if you actually want this script to work.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>As you probably noticed, there are quite a few similarities between this script and the one we just showed you. As we did before, we define a constant named HKEY_LOCAL_MACHINE and then connect to the WMI service. Once that\u2019s done we assign values to the variables strKeyPath (the path within the registry hive) and strValueName (the name of the registry value we want to read). That brings us to this line of code:<\/P><PRE class=\"codeSample\">objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue\n<\/PRE>\n<P>Here we\u2019re using the <B>GetStringValue<\/B> method to read the registry value Script 1. As you can see, we pass this method four parameters:<\/P>\n<TABLE class=\"\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\">\n<TBODY>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>HKEY_LOCAL_MACHIN<\/B>E, representing the registry hive.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>strKeyPath<\/B>, representing the path with that hive.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>strValueName<\/B>, representing the registry value we want to read.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>strValue<\/B>, an \u201cout\u201d parameter for storing the value read from strValueName.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>And you\u2019re right: we <I>didn\u2019t<\/I> assign a value to strValue, did we? That\u2019s the beauty of out parameters: we don\u2019t have to do anything. Instead, we merely provide a variable name to the GetStringValue method, and GetStringValue then goes ahead and assigns the appropriate value to the variable for us.<\/P>\n<P>Just WMI\u2019s way of saying thanks.<\/P>\n<P>Needless to say, our next step is to determine what value <I>did<\/I> get assigned to strValue:<\/P><PRE class=\"codeSample\">If strValue = &#8220;No&#8221; Then\n<\/PRE>\n<P>If strValue is No that means that the script hasn\u2019t been run on this machine yet. Therefore, we go ahead and run this script. In our sample script, that simply means echoing a value back to the screen:<\/P><PRE class=\"codeSample\">Wscript.Echo &#8220;This script will now run.&#8221;\n<\/PRE>\n<P>All you have to do is replace the preceding line of code with the line or lines that you want <I>your<\/I> script to execute.<\/P>\n<P>Now that the script has run we need to change the value in the registry from No to Yes. That\u2019s what this block of code is for:<\/P><PRE class=\"codeSample\">strValue = &#8220;Yes&#8221;\nobjRegistry.SetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue\n<\/PRE>\n<P>Nothing too fancy here: we assign the value <I>Yes<\/I> to the variable strValue, then call the <B>SetStringValue<\/B> method to write the new value to the registry.<\/P>\n<P>Now, suppose strValue <I>didn\u2019t<\/I> equal No. In that case, we\u2019re assuming two things: that strValue equals Yes, and that the script has already run on this computer. What do we do in that case? We do what the Scripting Guys do best: nothing. Instead, we just call the <B>Quit<\/B> method and terminate the script:<\/P><PRE class=\"codeSample\">Wscript.Quit\n<\/PRE>\n<P>And that should do it. Again, this isn\u2019t foolproof: obviously someone could go into the registry and manually change the value of Script 1 from Yes to No. If that happens then the script can be fooled into thinking it\u2019s never run on this particular machine. But it\u2019s generally safe to assume that won\u2019t happen. <\/P>\n<TABLE class=\"dataTable\" id=\"E6BAC\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. If that <I>is<\/I> a concern you could set up auditing on the key in question or monitor that key for changes. That won\u2019t prevent people from making the change, but at least you will be notified if and when they do.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>As for sending us pictures, well, we realize that most people <I>didn\u2019t<\/I> win a Dr. Scripto bobblehead doll. What can we do for those of you who didn\u2019t win? Nothing. Next time try a little harder, huh?<\/P>\n<P>No, hey, just kidding. As it turns out, the Scripting Guys have a few bobbleheads leftover, bobbleheads which are currently being held under lock-and-key at <A href=\"http:\/\/en.wikipedia.org\/wiki\/United_States_Bullion_Depository\" target=\"_blank\"><B>Fort Knox<\/B><\/A>. We\u2019ll be giving away a bunch of those at <A href=\"http:\/\/www.microsoft.com\/events\/teched2007\/default.mspx\" target=\"_blank\"><B>TechEd 2007<\/B><\/A>; if you\u2019re planning on going to TechEd be sure and swing by the TechNet Magazine booth, say hi to the Scripting Guys, and sign up for the drawing. And if you\u2019re <I>not<\/I> going to the conference, well, don\u2019t despair; in conjunction with TechEd we\u2019ll be holding a little contest which will give <I>everyone<\/I> a chance to win a bobblehead. We\u2019ll provide more details on that in a few weeks.<\/P>\n<P>Just remember, if you <I>do<\/I> win, don\u2019t show us your bobblehead. Just send us a picture of your prize instead.<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I ensure that a script runs only once on a computer?&#8212; ML Hey, ML. You know, we were going to start off today\u2019s column by saying, \u201cShow us your bobbleheads!\u201d However, we didn\u2019t want to have to explain to Microsoft people that there was nothing risqu\u00e9 or offensive in that [&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":[2,3,4,5],"class_list":["post-64953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-running","tag-scripting-guy","tag-scripting-techniques","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I ensure that a script runs only once on a computer?&#8212; ML Hey, ML. You know, we were going to start off today\u2019s column by saying, \u201cShow us your bobbleheads!\u201d However, we didn\u2019t want to have to explain to Microsoft people that there was nothing risqu\u00e9 or offensive in that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64953","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=64953"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64953\/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=64953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=64953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=64953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}