{"id":55943,"date":"2008-03-22T00:23:00","date_gmt":"2008-03-22T00:23:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/03\/22\/hey-scripting-guy-how-can-i-use-data-read-from-a-text-file-as-command-line-parameters-for-a-batch-file\/"},"modified":"2008-03-22T00:23:00","modified_gmt":"2008-03-22T00:23:00","slug":"hey-scripting-guy-how-can-i-use-data-read-from-a-text-file-as-command-line-parameters-for-a-batch-file","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-use-data-read-from-a-text-file-as-command-line-parameters-for-a-batch-file\/","title":{"rendered":"Hey, Scripting Guy! How Can I Use Data Read From a Text File as Command-Line Parameters For a Batch File?"},"content":{"rendered":"<p><img decoding=\"async\" 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\" \/> <\/p>\n<p>Hey, Scripting Guy! I&#8217;m trying to automate a tedious license server task. To do this, I need to loop through a text file line-by-line, grab out a user name, asset number, and license ID, and then pass those values to a batch file. How can I do all that?<\/p>\n<p>&#8212; DM<\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\" \/><img decoding=\"async\" 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 decoding=\"async\" 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> <\/p>\n<p>Hey, DM. Before we get started today <i>is<\/i> Friday, March 21, 2008 isn\u2019t it? We wanted to double-check that because \u2013 in the tradition if <a href=\"http:\/\/en.wikipedia.org\/wiki\/Slaughterhouse-Five\" target=\"_blank\"><b>Billy Pilgrim<\/b><\/a> \u2013 the Scripting Guys seem to have become unstuck in time.<\/p>\n<table id=\"EFD\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p><b>Note<\/b>. So how do you even <i>get<\/i> \u201cunstuck in time?\u201d Well, to tell you the truth, we don\u2019t know. Scripting Guy Peter Costantini would probably know, but the last we heard Peter had traveled back to the early 1930s to try and convince Chef Boyardee not to release <a href=\"http:\/\/www.chefboyardee.com\/tasteefood\/index.jsp\" target=\"_blank\"><b>Beefaroni<\/b><\/a>.<\/p>\n<p>And no, we have no idea <i>why<\/i> he\u2019s trying to do that.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>As it turns out, the other day the Scripting Guy who writes this column opened up the Script Center home page, and noted something a bit peculiar: he was looking at a home page that actually appeared way back in August, 2007. Upon clicking a few links here and there, he realized that the <i>entire<\/i> Script Center had reverted back to August 2007. Everything that had happened since then \u2013 the Scripting Guys\u2019 <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/teched07\/itmonday.mspx\"><b>trip to Barcelona<\/b><\/a>, the Christmas holidays, the <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games08.mspx\"><b>2008 Winter Scripting Games<\/b><\/a> \u2013 were gone.<\/p>\n<p>Now, admittedly, there are plenty of things that happened over the past few months that the Scripting Guy who writes this column would be <i>thrilled<\/i> to have disappear. On the other hand, he wasn\u2019t too-terribly excited about doing things like re-testing the 10,500 scripts that were submitted during the 2008 Scripting Games. Consequently, he checked with the Scripting Editor to verify that she, too had become unstuck in time. (And not just fashion-wise.) When it turned out she had, the Scripting Guys sent an email to Microsoft.com asking if someone there knew what was going on. (Always a silly question to ask <i>anyone<\/i> at Microsoft if they know what\u2019s going on, but we didn\u2019t know what else to do.)<\/p>\n<p>In the meantime, of course, we had work to do, which meant we had questions to answer. And yes, it\u2019s possible that we had already answered these questions, back in, say, October, 2007. However, because October, 2007 hadn\u2019t actually occurred yet we had no way of knowing that for sure. With that in mind, here\u2019s the answer to your question, DM. If we already answered this question, well, sit tight; there\u2019s a good chance we\u2019ll become unstuck in time again and that will change. Either way, here\u2019s a script that can grab values out of a text file and then use those values as command-line parameters to a batch file:<\/p>\n<pre class=\"codeSample\">Const ForReading = 1\n\nSet objShell = CreateObject(\"Wscript.Shell\")\n\nSet objRegEx = CreateObject(\"VBScript.RegExp\")\nobjRegEx.Pattern = \"\\d{1,}\"\n\nSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\nSet objFile = objFSO.OpenTextFile(\"C:\\Scripts\\Test.txt\", ForReading)\n\nDo Until objFile.AtEndOfStream\n    strLine = objFile.ReadLine\n    arrItems = Split(strLine, \" \")\n    strUserName = arrItems(0)\n    strAsset = arrItems(1)\n\n    strLicenseID = arrItems(5)\n   \n    Set colMatches = objRegEx.Execute(strLicenseID)  \n    strLicense = colMatches(0).Value\n\n    strCommand = \"%compsec% \/c C:\\Scripts\\Test.cmd \" &amp; strUserName &amp; \" \" &amp; strAsset &amp; \" \" &amp; strLicense\n    objShell.Run strCommand, 1, True\nLoop\n\nobjFile.Close\n<\/pre>\n<p>Before we launch into a description of how this script works let\u2019s take a look at the sample text file that DM sent us:<\/p>\n<pre class=\"codeSample\">Username1 asset1 asset1 (v24) (licserver\/1000 1111), start Wed 3\/19 8:50\nUsername2 asset2 asset2 (v24) (licserver\/1000 1112), start Wed 3\/19 8:55\nUsername3 asset3 asset3 (v24) (licserver\/1000 1113), start Wed 3\/19 8:59\n<\/pre>\n<p>As DM noted in his email, he needs to grab three items from each line in the text file. More specifically, he needs to grab the following:<\/p>\n<table border=\"0\" cellSpacing=\"0\" cellPadding=\"0\">\n<tbody>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>The user name (in line 1, that\u2019s <b>Username1<\/b>).<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>The asset ID (<b>asset1<\/b>).<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>The license number. For line 1, that\u2019s going to be <b>1111<\/b>, the last number within the string <b>(licserver\/1000 1111)<\/b>.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>So how are we supposed to ferret out that information? You know what? We\u2019re as curious to find out as you are. Let\u2019s keep reading and see what happens.<\/p>\n<table id=\"ETF\" 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>. If you\u2019ve become unstuck in time and thus have already read the answer and know how the script works, well, please keep this information to yourself. It would be a shame if you spoiled the surprise for everyone else.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>The script kicks off by defining a constant named ForReading and setting the value to 1; we\u2019ll use this constant when we open our text file. After defining the constant we then create an instance of the <b>Wscript.Shell<\/b> object, the object we\u2019ll need in order to call an application (or, in this case, a batch file) from within our script.<\/p>\n<p>Our next task is to create an instance of the <b>VBScript.RegExp<\/b> object, an object that enables us to use regular expressions within our script. We\u2019ll talk more about the regular expression object \u2013 and why we need it \u2013 in a few minutes. For now, we\u2019ll simply note that we set the value of the object\u2019s <b>Pattern<\/b> property using this line of code:<\/p>\n<pre class=\"codeSample\">objRegEx.Pattern = \"\\d{1,}\"\n<\/pre>\n<p>If you\u2019re not familiar with regular expressions, the Pattern property specifies the target value that we\u2019re looking for. (If you\u2019re not familiar with regular expressions you might also want to see our <a href=\"http:\/\/technet.microsoft.com\/en-us\/magazine\/cc137729.aspx\" target=\"_blank\"><b>TechNet Magazine article<\/b><\/a> on the subject.) Using standard regular expression syntax, the <b>\\d<\/b> means that we want to search for a number. Which number? It doesn\u2019t matter; any digit between 0 and 9 will do. The <b>{1,}<\/b> means that we need to find at least one digit; if we have more than one digit in succession, well, that\u2019s cool, too. In other words, the syntax <b>\\d{1,}<\/b> will find the value <i>1<\/i>. It will also find the value <i>32<\/i>, the value, <i>732829<\/i>, the value <i>3747347324932<\/i>, etc. etc.<\/p>\n<table id=\"EJH\" 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>. In DM\u2019s sample file the license ID is always four digits; couldn\u2019t we have specified that we wanted to search for a four-digit number and <i>only<\/i> a four-digit number? Sure; in that case we would have used <i>this<\/i> syntax: <b>\\d{4} <\/b>(find only four consecutive digits). However, we have no guarantee that <i>all<\/i> the license IDs are four digits; DM might very well have a license ID of 835 or a license ID of 67453. This way we\u2019re covered regardless of how many digits appear in the license ID.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>As soon as we configure the regular expression object we create an instance of the <b>Scripting.FileSystemObject<\/b>, then use this line of code to open the file C:\\Scripts\\Test.txt for reading:<\/p>\n<pre class=\"codeSample\">Set objFile = objFSO.OpenTextFile(\"C:\\Scripts\\Test.txt\", ForReading)\n<\/pre>\n<p>And now the fun begins.<\/p>\n<p>To start, we set up a Do Until loop that runs until the file\u2019s <b>AtEndOfStream<\/b> property is True; that simply means we\u2019re going to keep running through this loop until we\u2019ve read all the lines in the file. And speaking of reading lines in the file, that\u2019s the very first thing we do in our loop; we use this line of code to read in the first line in the text file and store it in a variable named strLine:<\/p>\n<pre class=\"codeSample\">strLine = objFile.ReadLine\n<\/pre>\n<p>What does that mean? That means that, the first time through the loop, strLine will be equal to this:<\/p>\n<pre class=\"codeSample\">Username1 asset1 asset1 (v24) (licserver\/1000 1111), start Wed 3\/19 8:50\n<\/pre>\n<p>So are we done yet? Well, no, not quite; after all, we still have to tease out the user name, asset number, and license ID. To do all that, we first use VBScript\u2019s <b>Split<\/b> function to turn strLine into an array named arrItems:<\/p>\n<pre class=\"codeSample\">arrItems = Split(strLine, \" \")\n<\/pre>\n<p>By splitting strLine on each and every blank space, we end up with an array that contains the following items:<\/p>\n<pre class=\"codeSample\">Username1 \nasset1 \nasset1 \n(v24) \n(licserver\/1000 \n1111), \nstart \nWed \n3\/19 \n8:50\n<\/pre>\n<p>So is this array really all that useful to us? You bet it is. We need to retrieve the user name; well, guess what item 0 in the array just happens to be? (We won\u2019t keep you in suspense: item 0 \u2013 the first item in the array \u2013 is the user name.) You say we need the user name? That\u2019s fine; this line of code takes that user name (item 0 in the array) and assigns it to a variable named strUserName:<\/p>\n<pre class=\"codeSample\">strUserName = arrItems(0)\n<\/pre>\n<p>We then use the same approach to grab the asset number (item 1 in the array) and assign <i>that<\/i> value to a variable named strAsset:<\/p>\n<pre class=\"codeSample\">strAsset = arrItems(1)\n<\/pre>\n<p>That leaves us with the license ID. As it turns out, the license ID is item 5 in the array. (Remember, the first item in an array always has the index number 0.) That\u2019s great, except for one problem; item 5 in the array currently looks like this:<\/p>\n<pre class=\"codeSample\">1111),\n<\/pre>\n<p>That\u2019s not so great.<\/p>\n<p>There are several different ways that we could extract the license ID from this value. We decided that the most generic (and thus most useful and flexible) way to do this was to use a regular expression. With that in mind we assign the value of array item 5 to a variable named strLicenseID, then use the <b>Execute<\/b> method to search that value for consecutive digits:<\/p>\n<pre class=\"codeSample\">Set colMatches = objRegEx.Execute(strLicenseID)\n<\/pre>\n<p>When you call the Execute method any matches that are found (that is, any instances of the target value) are stored in a collection; in this case that\u2019s a collection we named colMatches. Based on the structure of our text file, we know that there will be only one match; hence we can get at the license ID (1111) simply by grabbing the value of item 0 in the collection:<\/p>\n<pre class=\"codeSample\">strLicense = colMatches(0).Value\n<\/pre>\n<p>At this point we have all the information we need to call our batch file. That batch file requires us to pass three command-line parameters, something like this:<\/p>\n<pre class=\"codeSample\">C:\\Scripts\\Test.cmd Username1 asset1 1111\n<\/pre>\n<p>That\u2019s the command we would need to type into the command window in order to run the batch file. With one minor addition, that\u2019s also the command we construct with this line of code:<\/p>\n<pre class=\"codeSample\">strCommand = \"%compsec% \/c C:\\Scripts\\Test.cmd \" &amp; strUserName &amp; \" \" &amp; strAsset &amp; \" \" &amp; strLicense\n<\/pre>\n<p>As you can see, we\u2019re simply combining the path to the batch file with the values of the variables strUserName, strAsset, and strLicense, taking care to insert a blank space between each parameter. Oh, and at the very beginning of the string we insert this construction: <b>%comspec% \/c<\/b>. What\u2019s that for? Well, that simply tells the script that we want to run this command in a new console window (<b>%comspec%<\/b>) and that we want that window to close as soon as the batch file finishes running (<b>\/c<\/b>). Depending on what your batch file actually does this might be superfluous; however, this helps ensure that the batch file doesn\u2019t run and then simply sit there until you manually close the command window. <\/p>\n<p>The net result of all this? The first time through the loop the variable strCommand will end up equal to this:<\/p>\n<pre class=\"codeSample\">%compsec% \/c C:\\Scripts\\Test.cmd Username1 asset1 1111\n<\/pre>\n<p>Once we\u2019ve constructed our command we can then call our batch file using the Shell object\u2019s <b>Run<\/b> method:<\/p>\n<pre class=\"codeSample\">objShell.Run strCommand, 1, True\n<\/pre>\n<table id=\"ECCAC\" 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>. In case you\u2019re wondering, the second parameter \u2013 <b>1<\/b> \u2013 tells the script to run the batch file in a normal window. The third parameter \u2013 <b>True <\/b>\u2013 tells the script to wait until the batch file finishes before moving on to the next line of code.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>And then it\u2019s back to the top of the loop where we repeat the process with the next line in the text file. When we\u2019re all done we use the <b>Close<\/b> method to close Test.txt and then call it a day.<\/p>\n<p>In case you\u2019re wondering, we never <i>did<\/i> hear back from Microsoft.com. (Of course, we have no idea what month \u2013 or year \u2013 they might have sent their reply from.) However, a few minutes after we sent the email the Script Center magically reverted back to its March, 2008 edition. As far as we know, that\u2019s a good thing. On the other hand, there\u2019s always the chance that Microsoft.com was correct and the date really <i>was<\/i> August, 2007. If that\u2019s the case, then the Scripting Guys have now skipped time <i>ahead<\/i> several months. If you didn\u2019t have a Christmas this year or didn\u2019t get any birthday presents, well, that\u2019s our fault, and we apologize for that. But don\u2019t despair; maybe the next time we become unstuck in time you\u2019ll get to have <i>two<\/i> birthdays. <\/p>\n<table id=\"EGDAC\" 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>. Good point: maybe the Scripting Editor <i>has<\/i> been messing with the space-time continuum in order to ensure that she never has another birthday. We\u2019ll look into that and let you know. (Although it doesn\u2019t seem to be working too well, if you know what we mean.)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I&#8217;m trying to automate a tedious license server task. To do this, I need to loop through a text file line-by-line, grab out a user name, asset number, and license ID, and then pass those values to a batch file. How can I do all that? &#8212; DM Hey, DM. Before we [&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":[3,4,14,5],"class_list":["post-55943","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-scripting-guy","tag-scripting-techniques","tag-text-files","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I&#8217;m trying to automate a tedious license server task. To do this, I need to loop through a text file line-by-line, grab out a user name, asset number, and license ID, and then pass those values to a batch file. How can I do all that? &#8212; DM Hey, DM. Before we [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55943","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=55943"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55943\/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=55943"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=55943"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=55943"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}