{"id":55263,"date":"2008-06-26T18:20:00","date_gmt":"2008-06-26T18:20:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/06\/26\/hey-scripting-guy-how-can-i-copy-files-based-on-multiple-criteria\/"},"modified":"2008-06-26T18:20:00","modified_gmt":"2008-06-26T18:20:00","slug":"hey-scripting-guy-how-can-i-copy-files-based-on-multiple-criteria","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-copy-files-based-on-multiple-criteria\/","title":{"rendered":"Hey, Scripting Guy! How Can I Copy Files Based on Multiple Criteria?"},"content":{"rendered":"<p><img decoding=\"async\" height=\"34\" width=\"34\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" align=\"left\" alt=\"Hey, Scripting Guy! Question\" border=\"0\" title=\"Hey, Scripting Guy! Question\" class=\"nearGraphic\" \/><\/p>\n<p>Hey, Scripting Guy! How can I match multiple criteria in a file name? I need to copy all the files in a folder that are less than 24 hours old, and that have file names beginning with the letters <i>FS<\/i>, <i>CG<\/i>, or <i>GPS<\/i>. How can I do that?<\/p>\n<p>&#8212; EM<\/p>\n<p><img decoding=\"async\" height=\"5\" width=\"5\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" alt=\"Spacer\" border=\"0\" \/><img decoding=\"async\" height=\"34\" width=\"34\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" align=\"left\" alt=\"Hey, Scripting Guy! Answer\" border=\"0\" title=\"Hey, Scripting Guy! Answer\" class=\"nearGraphic\" \/><a href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><img decoding=\"async\" height=\"288\" width=\"120\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" align=\"right\" alt=\"Script Center\" border=\"0\" title=\"Script Center\" class=\"farGraphic\" \/><\/a><\/p>\n<p>Hey, EM. You know, today is an exciting day at Microsoft; it&rsquo;s the day when we get our Spam Notification. The Spam Notification is a list of all the emails that were addressed to us but were stopped by our &ldquo;Spam Quarantine filtering service.&rdquo; The Scripting Guy who writes this column loves to get the monthly Spam Notification, because he gets a kick out of looking at the Subject lines of the emails that have been tagged as Spam. Now, for better or worse, a lot of those Subject lines can&rsquo;t be (or at least <i>shouldn&rsquo;t<\/i> be) published on TechNet; you&rsquo;ll have to wait for the unrated director&rsquo;s cut of <i>Hey, Scripting Guy!<\/i> to see those. Nevertheless, there are a few intriguing Subject lines that we <i>can<\/i> print:<\/p>\n<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" class=\"listBullet\">&bull;<\/td>\n<td class=\"listItem\">\n<p><b>flimflam cableway<\/b>. This would be a great name for a movie star: <i>Summer Romance<\/i>, starring Kate Hudson and Flimflam Cableway.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" class=\"listBullet\">&bull;<\/td>\n<td class=\"listItem\">\n<p><b>Tablet of happiness<\/b>. We assume this a pill of some kind, although it would be very cool if it was a tablet of <i>paper<\/i> that made you happy.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" class=\"listBullet\">&bull;<\/td>\n<td class=\"listItem\">\n<p><b>Dont let her laugh at you again<\/b>. Usually not a problem for the Scripting Guy who writes this column: no one <i>ever<\/i> laughs at him, no matter how hard he tries. Admit it: you&rsquo;re not laughing now, are you? That&rsquo;s what we thought.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" class=\"listBullet\">&bull;<\/td>\n<td class=\"listItem\">\n<p><b>No more falls in bed committed<\/b>. To be honest, we&rsquo;re not exactly sure what this means. But it sounds like good advice.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" class=\"listBullet\">&bull;<\/td>\n<td class=\"listItem\">\n<p><b>Favorite shop of Indiana Jones<\/b>. We never really stopped to think about where Indiana Jones does his shopping; in fact, Indiana Jones doesn&rsquo;t seem like the shopping type to us. But, then again, those fedoras don&rsquo;t grow on trees.<\/p>\n<p>Well, maybe on a fedora tree. But they don&rsquo;t have many of those in the Seattle area<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<table cellpadding=\"0\" cellspacing=\"0\" class=\"dataTable\" id=\"ESE\">\n<thead><\/thead>\n<tbody>\n<tr valign=\"top\" class=\"record\">\n<td>\n<p class=\"lastInCell\"><b>Note<\/b>. Do you have a hankering to look just like Indiana Jones? Then <a target=\"_blank\" href=\"http:\/\/www.thinkgeek.com\/apparel\/hats-ties\/a67f\/\"><b>buy your very own fedora<\/b><\/a> online. Or, if you prefer, pick up your own <a target=\"_blank\" href=\"http:\/\/www.thinkgeek.com\/geektoys\/warfare\/69de\/\"><b>Star Wars lightsaber<\/b><\/a>. Note that the lightsaber requires three AA batteries, just like Luke Skywalker&rsquo;s lightsaber.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>Anyway, you can see why we like Spam Notification day so much: it&rsquo;s fun to see all the different things people are trying to sell these days, even if we aren&rsquo;t always sure what those things are (e.g., &ldquo;Certainly blank,&rdquo; which we believe refers to the Achievements and Accomplishments section of the Scripting Guys&rsquo; recent performance review). However, we did notice one glaring omission: no one is offering a script that can look through a folder, identify files less than 24 hours old that have file names beginning with the letters <i>FS<\/i>, <i>CG<\/i>, or <i>GPS<\/i>, and then copy those files to another location. (Well, OK, so maybe <i>that&rsquo;s<\/i> what the email with the subject line What She Wants is all about. But we doubt it.) <\/p>\n<p>But that&rsquo;s OK. If Internet spammers aren&rsquo;t going to write a script like that then the Scripting Guys will do it themselves:<\/p>\n<pre class=\"codeSample\"><pre class=\"codeSample\">strComputer = \".\"\n\nSet objWMIService = GetObject(\"winmgmts:\\\\\" &amp; strComputer &amp; \"\\root\\cimv2\")\n\nSet colFiles = objWMIService.ExecQuery _\n    (\"ASSOCIATORS OF {Win32_Directory.Name='C:\\Scripts'} Where \" _\n        &amp; \"ResultClass = CIM_DataFile\")\n\nSet objRegEx = CreateObject(\"VBScript.RegExp\")\nobjRegEx.Pattern = \"^FS|^CG|^GPS.\"\n\nstrCurrentDate = Now\n\nFor Each objFile In colFiles\n    strFileDate = WMIDateStringToDate(objFile.CreationDate)\n    intHours = DateDiff(\"h\", strFileDate, strCurrentDate)\n    If intHours &lt;= 24 Then\n        strSearchString = objFile.FileName\n        Set colMatches = objRegEx.Execute(strSearchString)  \n        If colMatches.Count &gt; 0 Then\n            strNewFile = \"C:\\Test\\\" &amp; objFile.FileName &amp; \".\" &amp; objFile.Extension\n            objFile.Copy(strNewFile)\n        End If\n    End If\nNext\n\nFunction WMIDateStringToDate(dtmInstallDate)\n    WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) &amp; \"\/\" &amp; _\n        Mid(dtmInstallDate, 7, 2) &amp; \"\/\" &amp; Left(dtmInstallDate, 4) _\n            &amp; \" \" &amp; Mid (dtmInstallDate, 9, 2) &amp; \":\" &amp; _\n                Mid(dtmInstallDate, 11, 2) &amp; \":\" &amp; Mid(dtmInstallDate, _\n                    13, 2))\nEnd Function<\/pre>\n<p>Let&rsquo;s see what we have here. We start out in the same way many of our scripts start out: by binding to the WMI service on the local computer. After that we add the comment that we add to many of our scripts: yes, you <i>can<\/i> run this script against a remote computer. All you have to do is assign the name of that remote computer to the variable strComputer, like so:<\/p>\n<pre class=\"codeSample\">strComputer = \"atl-fs-001\"<\/pre>\n<p>Once we&rsquo;ve connected to the WMI service we can then use this line of code to retrieve a collection of all the files found in the folder C:\\Scripts:<\/p>\n<pre class=\"codeSample\">Set colFiles = objWMIService.ExecQuery _\n    (\"ASSOCIATORS OF {Win32_Directory.Name='C:\\Scripts'} Where \" _\n        &amp; \"ResultClass = CIM_DataFile\")<\/pre>\n<p>And yes, we know: EM doesn&rsquo;t want <i>all<\/i> the files in the folder C:\\Scripts; instead, she only wants files that were created in the past 24 hours, and that have file names starting with the characters <i>FS<\/i>, <i>CG<\/i>, or <i>GPS<\/i>. Unfortunately, though, it&rsquo;s very difficult to work with date-time values in a WMI query, and it&rsquo;s <i>impossible<\/i> to use regular expression matching in a WMI query. That means we don&rsquo;t have much choice but to retrieve a collection of all the files in the folder and then run a couple different tests (Was the file created in the past 24 hours? Does the file name meet one of our three criteria?) on each and every file.<\/p>\n<table cellpadding=\"0\" cellspacing=\"0\" class=\"dataTable\" id=\"ESG\">\n<thead><\/thead>\n<tbody>\n<tr valign=\"top\" class=\"record\">\n<td>\n<p><b>Note<\/b>. Admittedly, we don&rsquo;t <i>have<\/i> to use WMI here; for example, we could use the FileSystemObject instead. However, we still can&rsquo;t use just one query to retrieve the exact files we want; that&rsquo;s because the FileSystemObject doesn&rsquo;t have a query language of <i>any<\/i> kind. And while we probably <i>could<\/i> use Windows PowerShell to attack this problem with a single (albeit long) line of code, we&rsquo;d then run into two other problems: 1) EM isn&rsquo;t using Windows PowerShell; and, 2) with Windows PowerShell 1.0 we wouldn&rsquo;t be able to run this script against a remote computer.<\/p>\n<p>In other words, maybe we <i>do<\/i> have to use WMI here after all.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>After we retrieve our collection of files we create an instance of the <b>VBScript.RegExp<\/b> object, the object that lets us do regular expression matching in a VBScript script. That brings us to this line of code:<\/p>\n<pre class=\"codeSample\">objRegEx.Pattern = \"^FS|^CG|^GPS.\"<\/pre>\n<p>What we&rsquo;re doing here is defining the criteria for our regular expression search. In this case, we&rsquo;re looking for one of three possible matches. How do we know that there are <i>three<\/i> possible matches? Because of the pipe character (|), which serves the same function as the word <i>or<\/i>; in this <b>Pattern<\/b> we&rsquo;re looking for ^FS <i>or<\/i> we&rsquo;re looking for ^CG <i>or<\/i> we&rsquo;re looking for ^GPS. See how that works?<\/p>\n<p>That&rsquo;s nice, but what exactly are we searching for (i.e., what does the syntax <b>^FS<\/b> actually <i>mean<\/i>)? Well, in regular expressions the caret symbol (^) means &ldquo;at the beginning of the string.&rdquo; (Actually, the caret symbol has another meaning besides that, but we&rsquo;ll ignore that other meaning for now.) As it turns out, this syntax is remarkably easy to decipher: we&rsquo;re simply looking for the letters <i>FS<\/i> at the beginning of the string. And if we don&rsquo;t find those two letters we&rsquo;ll check to see if the letters <i>CG<\/i> or <i>GPS<\/i> can be found at the beginning of the string instead. If any of those things are true, then we have ourselves a match.<\/p>\n<p>Next we use the <b>Now<\/b> function to assign the current date and time to a variable named strCurrentDate. Why do we do that? That&rsquo;s right: we can&rsquo;t determine if a file was created in the past 24 hours unless we know the current date and time. And then &ndash; finally! &ndash; we&rsquo;re ready to start looping through our collection of files and checking to see if any of the file names meet our criteria.<\/p>\n<p>So what&rsquo;s the best way to loop through a collection of files? Well, it&rsquo;s hard to go wrong with a For Each loop that loops through that collection. Therefore, our first step is to, well, set up a For Each loop that loops through our collection of files:<\/p>\n<pre class=\"codeSample\">For Each objFile In colFiles<\/pre>\n<p>Inside this loop the first thing we do is execute the following line of code:<\/p>\n<pre class=\"codeSample\">strFileDate = WMIDateStringToDate(objFile.CreationDate)<\/pre>\n<p>What we&rsquo;re doing here is taking the value of the file&rsquo;s <b>CreationDate<\/b> property and then using that value to call a function named WMIDateStringToDate. As you probably know, WMI uses the UTC (Universal Time Coordinate) format for storing date-time values; that means that a date like June 26, 2008, 8:30 AM, might be stored like this:<\/p>\n<pre class=\"codeSample\">20080626083000.000000+480<\/pre>\n<p>Needless to say, that doesn&rsquo;t do us a lot of good. Therefore, we use the function WMIDateStringToDate to convert this to a &ldquo;normal&rdquo; date-time value. We won&rsquo;t discuss the UTC format or the workings of the WMIDateStringToDate function in any detail today; if you&rsquo;d like a little more information about these things take a peek at the <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/guide\/sas_wmi_fvwp.mspx\"><b>Microsoft Windows 2000 Scripting Guide<\/b><\/a>. Suffice to say that the function grabs the individual date-time pieces from the UTC value (for example, the first four digits in the CreationDate represent the year that the file was created) and creates a date-time value that VBScript can work with.<\/p>\n<p>And what exactly do we want VBScript to do with this converted date-time value? Well, we&rsquo;re going to ask it to use the <b>DateDiff<\/b> function to determine whether the file was created in the past 24 hours:<\/p>\n<pre class=\"codeSample\">intHours = DateDiff(\"h\", strFileDate, strCurrentDate)<\/pre>\n<p>What DateDiff does is subtract the file&rsquo;s creation date from the current date and time (stored in the variable strCurrentDate). Because we used the <b>&ldquo;h&rdquo;<\/b> parameter that means that DateDiff will return the difference in hours. In other words, if our first file was created 12 hours ago then DateDiff will return the value 12 (which we promptly stash in the variable intHours). <\/p>\n<p>At that point we can check to see if intHours is less than or equal to 24:<\/p>\n<pre class=\"codeSample\">If intHours &lt;= 24 Then<\/pre>\n<p>What if intHours <i>isn&rsquo;t<\/i> less than or equal to 24? That&rsquo;s fine; that just means that the file wasn&rsquo;t created in the past 24 hours. In turn, that means we simply go back to the top of the loop and try again with the next file in the collection.<\/p>\n<p>But what if intHours <i>is<\/i> less than or equal to 24? That means we need to check and see if the file name starts with any of our three designated letter sets. And how do we do <i>that<\/i>? Why, by running these two lines of code, of course:<\/p>\n<pre class=\"codeSample\">strSearchString = objFile.FileName\nSet colMatches = objRegEx.Execute(strSearchString)<\/pre>\n<p>In the first line we&rsquo;re simply taking the value of the <b>FileName<\/b> property (minus the file extension) and storing it in a variable named strSearchString. In line 2, we use the <b>Execute<\/b> method to run a regular expression search against this file name.<\/p>\n<p>And how do we know if the file name fit our criteria? That&rsquo;s easy; we just check the regular expression <b>Matches<\/b> collection; more specifically, we check to see if the collection&rsquo;s <b>Count<\/b> property is greater than 0:<\/p>\n<pre class=\"codeSample\">If colMatches.Count &gt; 0 Then<\/pre>\n<p>If the Count <i>is<\/i> greater than 0 that can mean only one thing: we have a match. In turn, that means we need to do <i>two<\/i> things: we need to specify the location to where we want to copy the file (a location that must consist of a complete file path, including file name and extension); and, we need to copy the file to that location. That&rsquo;s what these two lines of code are for:<\/p>\n<pre class=\"codeSample\">strNewFile = \"C:\\Test\\\" &amp; objFile.FileName &amp; \".\" &amp; objFile.Extension<br \/>objFile.Copy(strNewFile)<\/pre>\n<p>And then it&rsquo;s back to the top of the loop, where we do this all over again with the next file in the collection.<\/p>\n<p>And that should do it, EM. It&rsquo;s not <i>exactly<\/i> what you were after, but it should work. And, as a little bonus, we showed you how you can search for any one of three possible patterns in a single regular expression. Can&rsquo;t beat that, huh?<\/p>\n<p>Anyway, if that doesn&rsquo;t solve all your problems, EM, well, just let us know; after all, we have access to an email that promises to &ldquo;Put an end to your woes.&rdquo; That sounds pretty nice. (Well, for those of you who, unlike the Scripting Guys, actually <i>have<\/i> woes.) And, of course, there&rsquo;s always the Tablet of Happiness. Like we said, just let us know.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I match multiple criteria in a file name? I need to copy all the files in a folder that are less than 24 hours old, and that have file names beginning with the letters FS, CG, or GPS. How can I do that? &#8212; EM Hey, EM. You know, today [&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":[38,3,12,5],"class_list":["post-55263","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-files","tag-scripting-guy","tag-storage","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I match multiple criteria in a file name? I need to copy all the files in a folder that are less than 24 hours old, and that have file names beginning with the letters FS, CG, or GPS. How can I do that? &#8212; EM Hey, EM. You know, today [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55263","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=55263"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55263\/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=55263"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=55263"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=55263"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}