{"id":64143,"date":"2007-08-28T01:43:00","date_gmt":"2007-08-28T01:43:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/08\/28\/how-can-i-find-all-the-files-in-a-directory-tree-that-contain-a-specific-word-or-phrase\/"},"modified":"2007-08-28T01:43:00","modified_gmt":"2007-08-28T01:43:00","slug":"how-can-i-find-all-the-files-in-a-directory-tree-that-contain-a-specific-word-or-phrase","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-find-all-the-files-in-a-directory-tree-that-contain-a-specific-word-or-phrase\/","title":{"rendered":"How Can I Find All the Files in a Directory Tree that Contain a Specific Word or Phrase?"},"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 find all the files in a directory tree that contain a specified phrase?<BR><BR>&#8212; PB <\/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, PB. OK, so picture this: for the first time in a couple of months, the Scripting Guy who writes this column and the Scripting Son are playing basketball. The Scripting Son has a comfortable lead, but the Scripting Guy who writes this column makes a desperate comeback, sinking four three-pointers in a row and tying the score. With the gym about to close for the night, everything has come down to this: next basket wins.<\/P>\n<P>As it turns out, the Scripting Guy who writes this column has the ball. He dribbles down to the baseline and then, for some stupid reason, he stops dribbling. (If you\u2019re not a basketball fan, picking up your dribble while down on the baseline isn\u2019t a particularly good thing to do.) Thanks to his own stupidity, the Scripting Guy who writes this column is now trapped: he has the baseline on one side of him and the Scripting Son, who\u2019s a good 7 inches taller than his father, on the other side. Thinking quickly (or at least as quickly as a Scripting Guy <I>can<\/I> think) he pivots one way, pivots back the other way, jumps up in the air, and then flips the ball, underhanded <I>and <\/I>left-handed, beneath the Scripting Son\u2019s outstretched arm. The ball rattles off the backboard and drops through the hoop. Game over! <\/P>\n<P>\u201cThat was so lucky,\u201d said the Scripting Son.<\/P>\n<P>Luck?!? Obviously the Scripting Son has no idea what luck is. Making a basket in basketball isn\u2019t lucky. No, lucky would be someone writing in to ask how he or she could locate all the files in a directory tree that contain a specified phrase, and then just happening to have a script lying around that does that very thing.<\/P>\n<P>You know, a script like this one:<\/P><PRE class=\"codeSample\">On Error Resume Next<\/p>\n<p>Set objConnection = CreateObject(&#8220;ADODB.Connection&#8221;)\nSet objRecordSet = CreateObject(&#8220;ADODB.Recordset&#8221;)<\/p>\n<p>objConnection.Open &#8220;Provider=Search.CollatorDSO;Extended Properties=&#8217;Application=Windows&#8217;;&#8221;<\/p>\n<p>objRecordSet.Open &#8220;SELECT System.ItemPathDisplay FROM SYSTEMINDEX WHERE Contains(&#8216;Alice&#8217;) &#8221; &amp; _\n    &#8220;AND System.ItemPathDisplay LIKE &#8216;C:\\Scripts\\%'&#8221;, objConnection<\/p>\n<p>objRecordSet.MoveFirst<\/p>\n<p>Do Until objRecordset.EOF\n    Wscript.Echo objRecordset.Fields.Item(&#8220;System.ItemPathDisplay&#8221;)\n    objRecordset.MoveNext\nLoop\n<\/PRE>\n<P>Before we go any further we should note that this script uses <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/desktop\/wdsearch.mspx\"><B>Windows Desktop Search 3.0<\/B><\/A>, a relatively new, fully-scriptable search technology that is included in Windows Vista (and can be downloaded and installed on other versions of Windows). We opted to use this approach for two reasons:<\/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>It\u2019s much easier to access all the folders in a folder tree using Desktop Search than to use WMI or the FileSystemObject. Performing this task using WMI or the FileSystemObject would require writing some crazy <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/feb05\/hey0218.mspx\"><B>recursive subroutine<\/B><\/A> that can get at each and every folder in a folder tree. Despite our reputation, the Scripting Guys don\u2019t like to do crazy things. (Not that we don\u2019t actually do them, mind you. But we don\u2019t like to do them.) <\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Windows Desktop Search can open \u2013 and search through \u2013 all sorts of file types, including Word documents, Excel spreadsheets, PowerPoint presentations, etc. Without using Desktop Search we\u2019d be limited to searching through text files. (OK, in theory we could search other document types, but we\u2019d have to include code that identifies, opens and searches Word documents plus code that identifies, opens and searches Excel spreadsheets plus code that identifies, opens and searches \u2013 well, you get the idea.)<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>Anyway, while there might be other ways we could perform this task, we decided that the <I>easiest<\/I> way to perform this task was to use Desktop Search. And, for the Scripting Guys at least, the easiest way is almost always the best way.<\/P>\n<P>So how exactly <I>do<\/I> we use Desktop Search to perform this task? Well, we start out by creating a pair of ADO (ActiveX Data Objects) objects; we\u2019ll use the <B>ADODB.Connection<\/B> object to connect to the Desktop Search file index, and we\u2019ll use the <B>ADODB.Recordset<\/B> object as a storehouse for any information returned by our query. After creating the two objects we then use the Connection object\u2019s <B>Open<\/B> method to bind us to Windows Desktop Search:<\/P><PRE class=\"codeSample\">objConnection.Open &#8220;Provider=Search.CollatorDSO;Extended Properties=&#8217;Application=Windows&#8217;;&#8221;\n<\/PRE>\n<TABLE class=\"dataTable\" id=\"EQE\" 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>. What all is going on in that line of code? Well, to be honest, we don\u2019t really know for sure. Nor do we really care. That\u2019s because this is simply boilerplate code: use this code exactly as-is any time you want to use Desktop Search and everyone will live happily ever after.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>After we open the data store we come to the heart-and-soul of any search script: the part where we specify exactly what it is we\u2019re searching for. In this case, we\u2019re calling the Recordset object\u2019s <B>Open<\/B> method, passing the method two parameters: the SQL query that contains our search criteria and an object reference to the Connection object (objConnection):<\/P><PRE class=\"codeSample\">objRecordSet.Open &#8220;SELECT System.ItemPathDisplay FROM SYSTEMINDEX WHERE Contains(&#8216;Alice&#8217;) &#8221; &amp; _\n    &#8220;AND System.ItemPathDisplay LIKE &#8216;C:\\Scripts\\%'&#8221;, objConnection\n<\/PRE>\n<P>As far as we\u2019re concerned, the one part of this command that <I>truly<\/I> matters is the SQL query itself:<\/P><PRE class=\"codeSample\">&#8220;SELECT System.ItemPathDisplay FROM SYSTEMINDEX WHERE Contains(&#8216;Alice&#8217;) &#8221; &amp; _\n    &#8220;AND System.ItemPathDisplay LIKE &#8216;C:\\Scripts\\%'&#8221;\n<\/PRE>\n<P>Let\u2019s see if we can figure out what\u2019s going on here. For our purposes today, the only thing we care about is the file path to any file that contains the word <I>Alice<\/I>. (By the way, this search is <I>not<\/I> case-sensitive; the search will locate <I>Alice<\/I>, <I>alice<\/I>, <I>ALICE<\/I>, or any other variation of the word.) When working with Desktop Search you need to specify each and every property value you want returned. Because the property <B>System.ItemPathDisplay<\/B> contains the file path we start our query out like this:<\/P><PRE class=\"codeSample\">SELECT System.ItemPathDisplay\n<\/PRE>\n<P>The next part of the query (FROM SYSTEMINDEX) is also boilerplate code; Desktop Search only has a single \u201ctable\u201d (SYSTEMINDEX) that we can query. That brings us to our WHERE clause, a clause that features a pair of criteria that must both be met for a file to be returned:<\/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>The file must include the word <I>Alice<\/I>. That\u2019s what the syntax <B>Contains(&#8216;<\/B><B>Alice<\/B><B>&#8216;)<\/B> is for: it tells the script to read the contents of the file and see if the word <I>Alice<\/I> can be found anywhere in those contents. (OK, technically Desktop Search has already read through the file; the script doesn\u2019t need to do so. But you get the idea.)<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>The file must be located somewhere in the C:\\Scripts folder tree. The syntax <B>System.ItemPathDisplay LIKE &#8216;C:\\Scripts\\%&#8217;<\/B> states that the file path (System.ItemPathDisplay) must begin with <B>C:\\Scripts\\<\/B>. The LIKE operator enables us to use a wildcard in our query; that wildcard happens to be the percent sign (%), which serves the same purpose as the asterisk does in, say, the dir command (e.g., dir C:\\Scripts\\Test.*). In other words, the percent sign causes this clause to be read as follows: \u201cShow me any file where the path starts with C:\\Scripts\\, regardless of what (if anything) comes after C:\\Scripts\\.\u201d In turn, thus enables us to locate files found in the C:\\Scripts folder (e.g., C:\\Scripts\\Test.txt) as well as files found in a subfolder of C:\\Scripts (e.g., C:\\Scripts\\Subfolder1\\Test.txt).<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P><I>Much<\/I> easier than writing a recursive subroutine that accomplishes the same seemingly-trivial feat of accessing all the files in a folder tree.<\/P>\n<P>After executing the query we use the <B>MoveFirst<\/B> method to move to the first record in the returned recordset. (We\u2019re not 100% sure that this is necessary, but better safe than sorry, right?) We then set up a Do Until loop that runs until we reach the end of the recordset; that is, until the recordset\u2019s <B>EOF<\/B> (and-of-file) property is True:<\/P><PRE class=\"codeSample\">Do Until objRecordset.EOF\n<\/PRE>\n<P>Inside this loop we don\u2019t do much; we simply echo back the value of the System.ItemPathDisplay property, then call the <B>MoveNext<\/B> method to move on and repeat the process with the next record in the recordset:<\/P><PRE class=\"codeSample\">Wscript.Echo objRecordset.Fields.Item(&#8220;System.ItemPathDisplay&#8221;)\nobjRecordset.MoveNext\n<\/PRE>\n<P>When all is said and done, we should get back a report similar to this:<\/P><PRE class=\"codeSample\">C:\\Scripts\\Scores.xls\nC:\\Scripts\\Alice2.txt\nC:\\Scripts\\Decoded.txt\nC:\\Scripts\\Decrypt.txt\nC:\\Scripts\\New Folder\\New Folder\\New Text Document.txt\n<\/PRE>\n<P>Notice two things here. For one, the first file in the list is actually an Excel spreadsheet file; as we noted earlier, Desktop Search has the ability to search inside Microsoft Office documents. (Among other things, Desktop Search can also search inside Adobe .PDF files.) Also note that the <I>last<\/I> file in the list is located in a sub-subfolder of C:\\Scripts, which means that we really <I>are<\/I> searching the entire C:\\Scripts folder tree.<\/P>\n<P>And that should do it, PB. Like we said, there might be other ways to accomplish this task, but Desktop Search makes the process very fast and very easy. And because Desktop Search has so many other cool capabilities, it\u2019s worth looking into anyway. (For more information, and more sample code, see our article <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/desktop\/wdsearch.mspx\"><B>Seek and Ye Shall Find<\/B><\/A>.)<\/P>\n<P>In case any of you are wondering, we should come clean and admit that the Scripting Son was right: the shot his father made to win the game really <I>was<\/I> pure luck. In fact, the Scripting Guy who writes this column wasn\u2019t even trying to <I>make<\/I> a basket: he was just hoping that, maybe, he could throw the ball off the backboard and then grab the rebound. No one was more surprised that he was when the ball actually went through the hoop.<\/P>\n<P>But, remember, that\u2019s between us: the Scripting Son doesn\u2019t really need to know how lucky the Scripting Guy who writes this column was. Instead, let him think that \u2013 for once \u2013 his Dad actually knew what he was doing.<\/P>\n<P>You know, you\u2019re right: there probably <I>isn\u2019t<\/I> much chance of that happening, is there?<\/P>\n<P>And for good reason.<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I find all the files in a directory tree that contain a specified phrase?&#8212; PB Hey, PB. OK, so picture this: for the first time in a couple of months, the Scripting Guy who writes this column and the Scripting Son are playing basketball. The Scripting Son has a comfortable [&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":[19,146,38,3,12,5],"class_list":["post-64143","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-activex-data-objects-ado","tag-databases","tag-files","tag-scripting-guy","tag-storage","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I find all the files in a directory tree that contain a specified phrase?&#8212; PB Hey, PB. OK, so picture this: for the first time in a couple of months, the Scripting Guy who writes this column and the Scripting Son are playing basketball. The Scripting Son has a comfortable [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64143","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=64143"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64143\/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=64143"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=64143"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=64143"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}