{"id":56103,"date":"2008-02-28T23:20:00","date_gmt":"2008-02-28T23:20:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/02\/28\/hey-scripting-guy-how-can-i-move-files-based-on-a-portion-of-the-file-name\/"},"modified":"2008-02-28T23:20:00","modified_gmt":"2008-02-28T23:20:00","slug":"hey-scripting-guy-how-can-i-move-files-based-on-a-portion-of-the-file-name","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-move-files-based-on-a-portion-of-the-file-name\/","title":{"rendered":"Hey, Scripting Guy! How Can I Move Files Based on a Portion of the File Name?"},"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! I have tens of thousands of files that all have a file name that includes a number bounded by two underscore characters; for example, P_19_L00.jpg. I need to figure out which number is embedded in a file name, then move that file to a folder named after that number. In this case, that means moving P_19_L00.jpg to the folder D:\\19. I have been searching the Internet for weeks and can&#8217;t come up with anything. Please help.<\/p>\n<p>&#8212; MGD<\/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, MGD. You know, this is kind of an unusual day for the Scripting Guy who writes this column. Why? Well, usually when someone fouls things up it&rsquo;s the Scripting Guy who writes this column. (Anyone else out there remember <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games07\/news.mspx\"><b>Event 8<\/b><\/a> from the 2007 Winter Scripting Games?) As it turns out, we sort of fouled things up with Event 5 in the Beginners Division of this year&rsquo;s <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/default.mspx\"><b>Winter Scripting Games<\/b><\/a>. (Which, we might add, continue to run until March 3<sup>rd<\/sup>. Still plenty of time to enter.) Event 5 was an admittedly-tough task, especially for beginners, and it resulted in a <i>lot<\/i> of people getting zeros for the event; it also resulted in a lot of people being less-than-thrilled with the score they received. But here&rsquo;s the weird part: that event does <i>not<\/i> belong to the Scripting Guy who writes this column; instead, it belongs to Scripting Guy Jean Ross. For once someone other than the Scripting Guy who writes this column has done something to cause problems!<\/p>\n<table cellpadding=\"0\" cellspacing=\"0\" class=\"dataTable\" id=\"ERD\">\n<thead><\/thead>\n<tbody>\n<tr valign=\"top\" class=\"record\">\n<td>\n<p class=\"lastInCell\"><b>Note<\/b>. Is that because it&rsquo;s hard to do something that causes problems unless you actually <i>do<\/i> something? We&rsquo;d better not say &hellip;.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>At any rate, remembering all the sympathy and support he&rsquo;s gotten every time <i>he<\/i> screws up, the Scripting Guy who writes this column would like to say this about Event 5 in the Beginners Division: if you feel you were wronged then send Scripting Guy Jean Ross an email, right away. Heck, send her 100 emails: let her know that she screwed up. Whatever you do, don&rsquo;t let her get away with this!<\/p>\n<p>Not that we&rsquo;re being vindictive or anything. We just feel it&rsquo;s important that Jean gets what she deserves.<\/p>\n<p>Um, by which we mean that you get what <i>you<\/i> deserve. Your welfare, and your score in the 2008 Winter Scripting Games, is our <i>only<\/i> concern. Really.<\/p>\n<table cellpadding=\"0\" cellspacing=\"0\" class=\"dataTable\" id=\"EOE\">\n<thead><\/thead>\n<tbody>\n<tr valign=\"top\" class=\"record\">\n<td>\n<p class=\"lastInCell\"><b>Note<\/b>. Although it <i>is<\/i> kind of nice to see Scripting Guy Jean Ross (who, until now, truly <i>was<\/i> practically perfect in every way) take a little heat for once.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>Anyway, drop Jean a line and let her know how you feel. What if you didn&rsquo;t even <i>compete<\/i> in Event 5? Well, so what? After all, you don&rsquo;t have to own a toxic waste dump in order to be concerned about pollution, right?<\/p>\n<p>Like we said, this is a highly unusual day for the Scripting Guy who writes this column. With that in mind, he decided that the best thing he could probably do is just try and go about his normal routine, to act as though nothing has changed. And what does his normal routine typically consist of? Well, fortunately for MGD, his normal routine typically involves writing scripts that can extract a portion of a file name and then move the file based on that piece of the file name:<\/p>\n<pre class=\"codeSample\"><pre class=\"codeSample\">Set objRegEx = CreateObject(\"VBScript.RegExp\")\n\nobjRegEx.Global = True   \nobjRegEx.Pattern = \"_\\d{1,}_\"\n\nSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\nSet objFolder = objFSO.GetFolder(\"C:\\Images\")\n\nSet colFiles = objFolder.Files\n\nFor Each objFile in colFiles\n    strSearchString = objFile.Name\n    Set colMatches = objRegEx.Execute(strSearchString)  \n\n    For Each strMatch in colMatches\n        strFolderName = strMatch.Value\n        strFolderName = Replace(strFolderName, \"_\", \"\")\n        strFolderName = \"D:\\\" &amp; strFolderName &amp; \"\\\"\n        If Not objFSO.FolderExists(strFolderName) Then\n            Set objNewFolder = objFSO.CreateFolder(strFolderName)\n        End If\n    Next\n\n    objFSO.MoveFile objFile.Path, strFolderName\nNext<\/pre>\n<p>As you can see, our script starts out by creating an instance of the <b>VBScript.RegExp<\/b> object, the object that enables us to use regular expressions within a VBScript script. Do we even <i>need<\/i> to use a regular expression in this script? Well, maybe we don&rsquo;t <i>need<\/i> to, but it definitely makes life much easier. Why? Well, MGD has file names similar to these:<\/p>\n<pre class=\"codeSample\">C:\\Images\\P_19_L00.jpg\nC:\\Images\\P_19_A01.jpg\nC:\\Images\\P_7658_T00.jpg\nC:\\Images\\P_7658_W04.jpg\nC:\\Images\\P_8291517_NI4.jpg<\/pre>\n<p>As you can see, the number of digits in the file name can &ndash; and does &ndash; vary. If the number of digits was always the same we wouldn&rsquo;t need a regular expression; we could just use the Mid function and grab the middle 2, or 3, or 4 characters. But that works only if the number of digits remains the same in each file name. In MGD&rsquo;s case, the number of digits varies from file name to file name. The Mid function can&rsquo;t deal with that; a regular expression can.<\/p>\n<p>That&rsquo;s why we decided to use a regular expression. <\/p>\n<p>After creating an instance of the RegExp object we configure two properties of this object. To begin with, we set the <b>Global<\/b> property to True; that simply tells the script to search for all instances of the target text. To be honest, that&rsquo;s not really important in this case; after all, no file name will ever have more than one instance of the target text anyway. However, more often than not you <i>will<\/i> want to find all instances of the target text. Therefore, we thought we&rsquo;d take the time to show you how to do that.<\/p>\n<p>In addition to configuring the Global property we also assign a value to the <b>Pattern<\/b> property:<\/p>\n<pre class=\"codeSample\">objRegEx.Pattern = \"_\\d{1,}_\"<\/pre>\n<p>The Pattern property is the spot where we define the target text (that is, the text we are looking for). Using standard <a target=\"_blank\" href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/1400241x(VS.85).aspx\"><b>regular expression syntax<\/b><\/a>, this line of code tells the script to look for an underscore character (<b>_<\/b>) followed by 1 or more numbers (<b>\\d{1,}<\/b>) followed by another underscore (<b>_<\/b>). That Pattern will find the <b>_19_<\/b> in P_19_L00.jpg. However, it won&rsquo;t find the <b>19A<\/b> in P_19A_L00.jpg. Why not? That&rsquo;s right: the Pattern tells the script that the <i>only<\/i> characters that can appear between the two underscores are the digits 0 through 9. P_19A_L00.jpg fails to make the cut because of the letter <i>A<\/i> between the two underscores.<\/p>\n<p>That actually makes sense, doesn&rsquo;t it? Wow, this <i>is<\/i> an unusual day!<\/p>\n<p>At this point we&rsquo;re ready to start moving files. To that end, the first thing we do is create an instance of the <b>Scripting.FileSystemObject<\/b>, then use this line of code to bind to the folder C:\\Images:<\/p>\n<pre class=\"codeSample\">Set objFolder = objFSO.GetFolder(\"C:\\Images\")<\/pre>\n<p>Once we&rsquo;ve made a connection to the folder we can use the following line of code to retrieve a collection of all the files in that folder:<\/p>\n<pre class=\"codeSample\">Set colFiles = objFolder.Files<\/pre>\n<p>That&rsquo;s a good point: because we&rsquo;re using the FileSystemObject (instead of WMI) that <i>does<\/i> pretty much restrict us to running this script on the local computer, doesn&rsquo;t it? There are two reasons we decided to go this route. For one thing, that&rsquo;s what MGD needs; he doesn&rsquo;t need to run this script against a remote computer. For another, running this script against a remote machine introduces a number of potential problems, including the difficulty in creating folders on a remote computer (although we do have <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/sept04\/hey0901.mspx\"><b>one solution<\/b><\/a> to that problem). <i>Could<\/i> we perform this task against a remote machine? Yes, albeit with a few limitations. If you have an interest in that let us know and we&rsquo;ll see if we can address that issue in a future column.<\/p>\n<p>For the present column, however, our next step is to set up a For Each loop to walk us through the collection of files found in C:\\Images. Inside that loop, we grab the value of the file&rsquo;s <b>Name<\/b> property and store it in a variable named strSearchString:<\/p>\n<pre class=\"codeSample\">strSearchString = objFile.Name<\/pre>\n<p>Once we&rsquo;ve done that we then call the Execute method to search the file name for the target text (numbers sandwiched between two underscore characters):<\/p>\n<pre class=\"codeSample\">Set colMatches = objRegEx.Execute(strSearchString)<\/pre>\n<p>If the target text can be found in the file name then all instances of that target text will be stored in a collection we named colMatches. To get at <i>that<\/i> information all we have to do is set up a second For Each loop, this one designed to walk through all the items in the colMatches collection:<\/p>\n<pre class=\"codeSample\">For Each strMatch in colMatches<\/pre>\n<p>So what are we going to do inside this second loop? Well, for starters, we&rsquo;re going to retrieve the matching text by assigning the match&rsquo;s <b>Value<\/b> property to a variable named strFolderName: <\/p>\n<pre class=\"codeSample\">strFolderName = strMatch.Value<\/pre>\n<p>That&rsquo;s going to make strFolderName equal to, say, this:<\/p>\n<pre class=\"codeSample\">_19_<\/pre>\n<p>Good observation: if it wasn&rsquo;t for those pesky underscore characters that <i>would<\/i> be the folder name we wanted, wouldn&rsquo;t it? OK, then why don&rsquo;t we just rid of those underscore characters:<\/p>\n<pre class=\"codeSample\">strFolderName = Replace(strFolderName, \"_\", \"\")<\/pre>\n<p>All we&rsquo;re doing here is using the <b>Replace<\/b> function to replace something (any underscore characters) with absolutely nothing.<\/p>\n<table cellpadding=\"0\" cellspacing=\"0\" class=\"dataTable\" id=\"E3AAC\">\n<thead><\/thead>\n<tbody>\n<tr valign=\"top\" class=\"record\">\n<td>\n<p class=\"lastInCell\"><b>Note<\/b>. Did Microsoft use the Replace function when they added the Scripting Editor to the Scripting Guys team? As a matter of fact, they &ndash; well, never mind. We better not get into that, either.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>The net result of all this is that strFolderName will now be equal to <i>19<\/i>. That&rsquo;s better, but it&rsquo;s still not what we need in order to move files; to do that we need a complete path, like <i>D:\\19\\<\/i>. That&rsquo;s what this line of code is for:<\/p>\n<pre class=\"codeSample\">strFolderName = \"D:\\\" &amp; strFolderName &amp; \"\\\"<\/pre>\n<p>As soon as we have a complete folder path we can then use this line of code to determine whether or not the specified folder already exists:<\/p>\n<pre class=\"codeSample\">If Not objFSO.FolderExists(strFolderName) Then<\/pre>\n<p>If D:\\19 <i>does<\/i> exist, well, that&rsquo;s great; that means we can simply continue on with the rest of the script. If D:\\19 <i>doesn&rsquo;t<\/i> exit, well, then we use the following line of code to create a new folder by that name:<\/p>\n<pre class=\"codeSample\">Set objNewFolder = objFSO.CreateFolder(strFolderName)<\/pre>\n<p>And once we&rsquo;ve done all that we can finally move the file P_19_L00.jpg from the folder C:\\Images to the folder D:\\19; that&rsquo;s what we&rsquo;re doing here:<\/p>\n<pre class=\"codeSample\">objFSO.MoveFile objFile.Path, strFolderName<\/pre>\n<p>From there we simply repeat the process with the next file in the collection. <\/p>\n<p>And that&rsquo;s all we have to do. By the time the script finishes running each file in the folder C:\\Images (or at least each file that has the target text somewhere in its file name) will have been moved to the appropriate folder on drive D. Not bad, eh?<\/p>\n<p>That should do it, MGD; give the script a try and see what happens. As for the Scripting Guys, the team scoreboard now looks a little like this:<\/p>\n<p><b>Jean Ross<\/b><b>&rsquo; Major Mistakes<\/b><\/p>\n<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"numberedList\">\n<tbody>\n<tr valign=\"top\">\n<td align=\"right\" class=\"listNumber\">\n<p>1.<\/p>\n<\/td>\n<td>\n<p>Event 5 in the 2008 Winter Scripting Games<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><b>The Scripting Guy Who Writes This Column&rsquo;s Major Mistakes<\/b><\/p>\n<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"numberedList\">\n<tbody>\n<tr valign=\"top\">\n<td align=\"right\" class=\"listNumber\">\n<p>1.<\/p>\n<\/td>\n<td>\n<p>Event 8 in the 2007 Winter Scripting Games<\/p>\n<\/td>\n<\/tr>\n<tr valign=\"top\">\n<td align=\"right\" class=\"listNumber\">\n<p>2.<\/p>\n<\/td>\n<td>\n<p>The Anti-Spyware Thing<\/p>\n<\/td>\n<\/tr>\n<tr valign=\"top\">\n<td align=\"right\" class=\"listNumber\">\n<p>3.<\/p>\n<\/td>\n<td>\n<p>Speaking favorably of the Search Engine That Shall Not Be Named<\/p>\n<\/td>\n<\/tr>\n<tr valign=\"top\">\n<td align=\"right\" class=\"listNumber\">\n<p>4.<\/p>\n<\/td>\n<td>\n<p>Making fun of Microsoft Bob in a Script Center article<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Etc., etc., etc. (The entire list goes on for about 20 pages or so.)<\/p>\n<p>Hey, Jean: looks like we&rsquo;re even now, eh?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I have tens of thousands of files that all have a file name that includes a number bounded by two underscore characters; for example, P_19_L00.jpg. I need to figure out which number is embedded in a file name, then move that file to a folder named after that number. In this case, [&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,174,3,4,12,5],"class_list":["post-56103","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-files","tag-regular-expressions","tag-scripting-guy","tag-scripting-techniques","tag-storage","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I have tens of thousands of files that all have a file name that includes a number bounded by two underscore characters; for example, P_19_L00.jpg. I need to figure out which number is embedded in a file name, then move that file to a folder named after that number. In this case, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/56103","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=56103"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/56103\/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=56103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=56103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=56103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}