{"id":63733,"date":"2007-10-24T23:26:00","date_gmt":"2007-10-24T23:26:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/10\/24\/hey-scripting-guy-how-can-i-move-files-based-on-a-value-in-the-file-name\/"},"modified":"2007-10-24T23:26:00","modified_gmt":"2007-10-24T23:26:00","slug":"hey-scripting-guy-how-can-i-move-files-based-on-a-value-in-the-file-name","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-move-files-based-on-a-value-in-the-file-name\/","title":{"rendered":"Hey, Scripting Guy! How Can I Move Files Based on a Value in the File Name?"},"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! I have a bunch of files that I need to move to new folders; the folder a given file will be moved to is based on the year, a value that appears in the file name. How can I write a script to move these files?<BR><BR>&#8212; LP<\/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, LP. Before we launch into today\u2019s column, we should clarify a couple of points which came up in an \u201cEditor\u2019s Note\u201d added to <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/oct07\/hey1023.mspx\"><B>yesterday\u2019s column<\/B><\/A>. Yesterday the Scripting Editor \u2013 for no apparent reason \u2013 felt the need to point out two things. To quote from her Note:<\/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>Last week, the Scripting Guy who writes this column mentioned the Washington vs. Oregon football game. This week he didn\u2019t. Enough said.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>The Scripting Guy who writes this column predicted the winner of the World Series. He also mentioned public ridicule\u2026Boston Red Sox fans, feel free to ridicule.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<TABLE id=\"EID\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P><B>Note<\/B>. No, we don\u2019t hold this unprovoked attack against her at all. As it turns out, the Scripting Editor got a ticket yesterday morning for parking her broom in a no-parking zone, and that obviously affected her attitude towards her work. Usually the Scripting Editor is out-going, fun-loving, and a sheer delight to be around.<\/P>\n<P>Or at least she would be if we had a different Scripting Editor.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>At any rate, in response to that Editor\u2019s Note the Scripting Guy who writes this column feels the need to point out two things himself:<\/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>Whatever it was that Oregon and Washington played last Saturday it definitely <I>wasn\u2019t<\/I> a football game. 55-34? That\u2019s not football, that\u2019s \u2026 uh \u2026 something that isn\u2019t football. Besides, Oregon fans have to live in Oregon. To defeat their football team on top of that would be just plain cruel.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Although the Scripting Guy who writes this column <I>did<\/I> pick the Cleveland Indians to win the World Series (come on, Cleveland; you can\u2019t win 1 lousy game after taking a 3-games-to-1 lead?) he also gave himself an out by saying that, if his prediction did not hold up, he would simply travel back in time and change that prediction. This is something he plans to do later tonight. If you wake up tomorrow morning and discover that dinosaurs once again rule the world, well, then you\u2019ll know that his time-traveling expedition didn\u2019t go off exactly as planned.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>We should also note that the Scripting Editor has a tendency to point out, over and over again, that, \u201cIt takes you <I>forever<\/I> to get around to answering the day\u2019s question.\u201d To be honest, we have no idea what she means by that. After all, here we are only 7 or 8 paragraphs into today\u2019s column and we\u2019re already showing you a script that can move files to a new folder based on a year value that appears in the file name:<\/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 colFiles = objWMIService.ExecQuery _\n    (&#8220;ASSOCIATORS OF {Win32_Directory.Name=&#8217;C:\\Test&#8217;} Where &#8221; _\n        &amp; &#8220;ResultClass = CIM_DataFile&#8221;)<\/p>\n<p>Set objRegEx = CreateObject(&#8220;VBScript.RegExp&#8221;)<\/p>\n<p>For Each objFile in colFiles\n    objRegEx.Global = True   \n    objRegEx.Pattern = &#8220;\\d{4}&#8221;<\/p>\n<p>    strSearchString = objFile.FileName\n    Set colMatches = objRegEx.Execute(strSearchString)<\/p>\n<p>    strYear = colMatches(0).Value<\/p>\n<p>    strNewFile = &#8220;C:\\Test\\&#8221; &amp; strYear &amp; &#8220;\\&#8221; &amp; objFile.FileName &amp; _\n        &#8220;.&#8221; &amp; objFile.Extension\n    objFile.Copy(strNewFile)\n    objFile.Delete\nNext\n<\/PRE>\n<P>Take forever, indeed. <I>Somebody<\/I> got up on the wrong side of the coven this morning!<\/P>\n<P>Before we talk about how this script works let\u2019s talk about the files we\u2019re dealing with. We\u2019re assuming we have a bunch of files with names similar to these:<\/P><PRE class=\"codeSample\">File2005a.txt\nFile2006a.txt\nFile2006b.txt\nFile2006c.txt\nFile2006d.txt\nFile2007a.txt\nFile2007b.txt\n<\/PRE>\n<P>The truth is, it doesn\u2019t really matter what the file names look like, with two exceptions: the year must be specified using 4 digits, and we can only have one 4-digit number in the name. Why that latter stipulation? Well, suppose we have a file name like this:<\/P><PRE class=\"codeSample\">File2005_3000.txt\n<\/PRE>\n<P>With a name like File2005_3000.txt we actually have <I>two<\/I> 4 digits numbers: 2005 and 3000. In this case we could probably guess which number is the year and which number is, well, some other number. But suppose have a file name like this:<\/P><PRE class=\"codeSample\">File1998_1999_2000.txt\n<\/PRE>\n<P>Now what do we do? Most likely file names like this follow some sort of hard-and-fast rule, e.g., \u201cThe second 4-digit number represents the year.\u201d However, because we don\u2019t know what your hard-and-fast rules are we can\u2019t account for them all. Therefore, we\u2019re only going to show you how to grab <I>all<\/I> the 4-digit values; it\u2019s up to you to determine which of those values represents the year.<\/P>\n<P>As for the script itself, we start out by connecting to the WMI service on the local computer. Could we perform this same task against a remote computer? We knew someone was going to ask that, which is why we opted to use WMI to move these files rather than, say, the FileSystemObject. And because we <I>did<\/I> use WMI, the answer to your question is this: yes, we <I>can<\/I> perform this same task against a remote computer. All we have to do is assign the name of that computer to the variable strComputer, like so:<\/P><PRE class=\"codeSample\">strComputer = &#8220;atl-fs-01&#8221;\n<\/PRE>\n<P>After we make our connection to the WMI service, we use this crazy-looking line of code to retrieve a collection of all the files found in the folder C:\\Test:<\/P><PRE class=\"codeSample\">Set colFiles = objWMIService.ExecQuery _\n    (&#8220;ASSOCIATORS OF {Win32_Directory.Name=&#8217;C:\\Test&#8217;} Where &#8221; _\n        &amp; &#8220;ResultClass = CIM_DataFile&#8221;)\n<\/PRE>\n<P>Like we said, it\u2019s crazy looking, which is the nature of WMI\u2019s <B>Associators Of<\/B> queries. However, all we\u2019re doing is retrieving all the files (instances of the <B>CIM_DataFile<\/B> class) that can be found in (are associators of) the folder C:\\Test (<B>Win32_Directory.Name=&#8217;C:\\Test&#8217;<\/B>). Once we have that collection in hand we next create an instance of the <B>VBScript.RegExp<\/B> object; at that point, we\u2019re ready to do some serious file management.<\/P>\n<P>What\u2019s that? What\u2019s the VBScript.RegExp object for? Well, that\u2019s the object that enables us to do a regular expressions search on each file name. We don\u2019t know, in advance, what year (or years) are going to appear in each file name; the year could be 1912, it could be 1987, it could be 2008. If we wanted to, we could create a seemingly-endless series of InStr commands that methodically look for each of these possibilities: 1913; 1914; 1915; 1916; 1917; etc. Alternatively, we could use a simple regular expression to search for any value consisting of 4 consecutive digits. Hmmm, do a <I>lot<\/I> of work, or do hardly any work at all? Try to guess which option the Scripting Guys chose.<\/P>\n<P>Speaking of the Scripting Guys, any time we get back a collection of all the files in a folder we can never resist setting up a For Each loop and looping through each and every file in that collection. Today\u2019s script is no exception. Consequently, we set up a For Each loop to do that very thing: loop through each and every file in our collection. Inside that loop, we kick things off by assigning values to two properties of our regular expressions object:<\/P><PRE class=\"codeSample\">objRegEx.Global = True   \nobjRegEx.Pattern = &#8220;\\d{4}&#8221;\n<\/PRE>\n<P>Setting the <B>Global<\/B> property to True simply tells the script to search for all instances of the target pattern; if this property were not set to True the script would find the first 4-digit number and then quit searching. In our case that doesn\u2019t matter; after all, our file names have only <I>one<\/I> 4-digit number. We just tossed this in because, in general, it\u2019s a good idea to set the Global property to True when doing a regular expressions search.<\/P>\n<P>As for the <B>Pattern<\/B> property, this is simply the value we\u2019re searching for. Granted, we don\u2019t know the <I>exact<\/I> value we\u2019re searching for. But because we\u2019re using regular expressions, we don\u2019t <I>have<\/I> to know the exact value; instead, we can search for a specified pattern (like, say, 4 consecutive digits). The <B>\\d{4}<\/B> is simply <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/1400241x.aspx\" target=\"_blank\"><B>regular expression syntax<\/B><\/A> for 4 consecutive digits. <\/P>\n<P>Once we\u2019ve assigned values to our two regular expression properties we then assign the <B>Name<\/B> of the first file in the collection to a variable named strSearchSrting:<\/P><PRE class=\"codeSample\">strSearchString = objFile.FileName\n<\/PRE>\n<P>From there we can call the <B>Execute<\/B> method to search the file name for any instances of our target pattern (4 consecutive digits):<\/P><PRE class=\"codeSample\">Set colMatches = objRegEx.Execute(strSearchString)\n<\/PRE>\n<P>Assuming we find an instance of the target pattern (something we can be pretty sure of in this case) those instances will all be stored in the regular expression <B>Matches<\/B> collection. Because the first such instance (and only instance) will be the year, and because the first such instance will be given an index number of 0, that means we can retrieve the actual year (the match <B>Value<\/B>) by using this line of code:<\/P><PRE class=\"codeSample\">strYear = colMatches(0).Value\n<\/PRE>\n<P>Just like that, the file year (or at least the year specified in the file name) will get stored in the variable strYear.<\/P>\n<P>The rest is easy. Once we know the year we can then construct a brand-new file path using this line of code:<\/P><PRE class=\"codeSample\">strNewFile = &#8220;C:\\Test\\&#8221; &amp; strYear &amp; &#8220;\\&#8221; &amp; objFile.FileName &amp; _\n    &#8220;.&#8221; &amp; objFile.Extension\n<\/PRE>\n<P>In that line of code we\u2019re simply stringing together the following values:<\/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><B>C:\\Test\\<\/B><\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>2005<\/B> (the file year, as stored in the variable strYear)<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>\\<\/B> (to separate the folder name from the file name)<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>File2005a<\/B> (the file name, stored in the FileName property)<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>.<\/B> (the period required to delineate the file extension)<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>txt<\/B> (the file extension, stored in the Extension property)<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>Put them altogether and they spell this:<\/P>\n<P>C:\\Test\\<B>2005<\/B>\\File2005a.txt<\/P>\n<P>The key part? The <B>2005<\/B> embedded in the middle of the path; that\u2019s the folder (C:\\Test\\2005) we\u2019ll be moving this file to.<\/P>\n<P>For some strange reason, WMI doesn\u2019t actually <I>have<\/I> a method for moving files. Therefore, we need to take a two-step approach to moving files: we first copy the original file to the new folder (C:\\Test\\2005), then we delete the original file (leaving the copy File2005a.txt in the 2005 folder). That\u2019s what these two lines of code are for:<\/P><PRE class=\"codeSample\">objFile.Copy(strNewFile)\nobjFile.Delete\n<\/PRE>\n<P>It\u2019s not as elegant as having a single Move command, but it accomplishes the same thing, albeit in one extra step.<\/P>\n<P>And then it\u2019s back to the top of the loop, where we repeat the process with the next file in the collection.<\/P>\n<TABLE id=\"EFBAC\" 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>. We should add that this script assumes that the target folders (e.g., the 2005 folder) already exist. What if those folders <I>don\u2019t<\/I> exist? In that case, take a peek at <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/sept07\/hey0918.mspx\"><B>one of our previous columns<\/B><\/A>, which provides a little more information on checking for the existence of a folder and, if the folder doesn\u2019t exist, creating it.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>That should do it, LP. Before we go we would also like to apologize to the Scripting Editor. Yesterday we stated that the Scripting Editor was third runner-up in the 1949 Miss Iowa Beauty Pageant. Needless to say, that made the Scripting Editor seem <I>far<\/I> older than she really is, a misconception we are truly sorry for creating. In truth, the Scripting Editor was third runner-up in the <I>1953<\/I> Miss Iowa Beauty Pageant, several years later than originally stated. <\/P>\n<TABLE id=\"EBCAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Scripting Guys Trivia<\/B>: At the time, the Scripting Editor was also the oldest person to ever win a major beauty contest in the USA. Amazing but true!<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Again, our apologies to both the Scripting Editor and our readers for any inconvenience or misconceptions this error might have caused. <\/P>\n<TABLE id=\"ENCAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Ed<\/B><B>itor\u2019s Note<\/B>: Given that the Scripting Guy who writes this column admitted, twice, that the Scripting Editor was fully capable of winning \u201ca major beauty contest,\u201d the Scripting Editor graciously accepts his apology. (Even though he\u2019s still off by quite a few years.)<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I have a bunch of files that I need to move to new folders; the folder a given file will be moved to is based on the year, a value that appears in the file name. How can I write a script to move these files?&#8212; LP Hey, LP. Before we launch [&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-63733","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! I have a bunch of files that I need to move to new folders; the folder a given file will be moved to is based on the year, a value that appears in the file name. How can I write a script to move these files?&#8212; LP Hey, LP. Before we launch [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63733","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=63733"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63733\/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=63733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=63733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=63733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}