{"id":55463,"date":"2008-05-30T01:52:00","date_gmt":"2008-05-30T01:52:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/05\/30\/hey-scripting-guy-how-can-i-search-for-a-specific-style-in-a-folder-full-of-microsoft-word-documents\/"},"modified":"2008-05-30T01:52:00","modified_gmt":"2008-05-30T01:52:00","slug":"hey-scripting-guy-how-can-i-search-for-a-specific-style-in-a-folder-full-of-microsoft-word-documents","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-search-for-a-specific-style-in-a-folder-full-of-microsoft-word-documents\/","title":{"rendered":"Hey, Scripting Guy! How Can I Search For a Specific Style in a Folder Full of Microsoft Word Documents?"},"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 have a folder with scores of Word documents in it. What I need to do is open each document, copy anything that uses the Heading 1 style, and then write that information (the file name and anything that uses the Heading 1 style) to a single text file. Is there a way to do this using a script?<br \/>&#8212; DN<\/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, DN. You know, there has been a lot of speculation lately about Windows 7, the next version of Windows. Microsoft has been uncharacteristically tight-lipped when it comes to Windows 7, which means that, all over the world, people have been asking the same question, \u201cJust what features<i> are<\/i> going to be included in Windows 7?\u201d Well, at the risk of losing our jobs the Scripting Guys have decided to lift the veil on Windows 7. Here, for the first time ever, are the key features you can expect to see in Windows 7:<\/p>\n<p><b>Grilled cheese sandwiches<\/b>. Yes, Windows 7 will be able to make you a grilled cheese sandwich on demand. To tell you the truth, we aren\u2019t sure why Microsoft hasn\u2019t made a bigger deal about this; after, just try to make a grilled cheese sandwich on a Macintosh. (Go on, we <i>dare<\/i> you!) We suspect that this is due to the fact that, in its initial release, you\u2019ll only be able to make a sandwich that uses Monterey Jack cheese; cheddar, American, and provolone probably won\u2019t be available until Service Pack 1. As for Colby or Muenster, well, all we can is this: the research goes on.<\/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>Legal disclaimer<\/b>. Please don\u2019t try to make a grilled cheese sandwich on your Macintosh. And no, we didn\u2019t dare you to try and make a grilled cheese sandwich on your Macintosh; where did you get <i>that<\/i> idea?<\/p>\n<p>Oh, right.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p><b>500 built-in television channels<\/b>. All the hardware will be built into the box, and all the channels will be free. And at any given time 492 of them will be showing the same rerun of <i>Everybody Loves Raymond<\/i>. <\/p>\n<p>And no, that wasn\u2019t an oversight; there\u2019s a reason why we didn\u2019t say that the channels would be <i>commercial<\/i>-free.<\/p>\n<p>Which reminds us: do you need a little something to wash down that grilled cheese sandwich? The Scripting Guys suggest Fabrikam Cola. Fabrikam: the soft drink that\u2019s almost a real cola drink.<\/p>\n<p><b>Touch screen capabilities<\/b>. Admittedly, this is still somewhat up in the air. The touch screen technology is present in the early builds of the product, but every time you touch the screen the computer goes, \u201cWhoa. What was that? Are you touching me? Are <i>you<\/i> touching <i>me<\/i>?\u201d Needless to say, there are still a few bugs to work out.<\/p>\n<p>And that\u2019s not all, far from it. There is also an unsubstantiated rumor going around the Microsoft campus that Windows 7 will include a script that lets you open each Microsoft Word document in a folder, copy any text that uses the Heading 1 style, and then writes that information to a text file. And you\u2019re right, that <i>would<\/i> be a pretty compelling reason to upgrade to Windows 7, wouldn\u2019t it? But guess what? You don\u2019t have to wait until Windows 7 to get a script like that; after all the Script Center is offering that very same capability today. Literally:<\/p>\n<pre class=\"codeSample\">Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\nSet objFolder = objFSO.GetFolder(\"C:\\Scripts\")\n\nSet objWord = CreateObject(\"Word.Application\")\nobjWord.Visible = True\n\nFor Each objFile in objFolder.Files\n    strFilePath = objFile.Path \n    strExtension = objFSO.GetExtensionName(strFilePath)\n\n    If strExtension = \"doc\" Then\n        strText = strText &amp; strFilePath &amp; vbCrLf\n        Set objDoc = objWord.Documents.Open(strFilePath)\n        Set objSelection = objWord.Selection\n\n        objSelection.Find.Forward = True\n        objSelection.Find.Format = True\n        objSelection.Find.Style = \"Heading 1\"\n\n        Do While True\n            objSelection.Find.Execute\n            If objSelection.Find.Found Then\n                strText = strText &amp; objSelection.Text &amp; vbCrLf\n            Else\n                Exit Do\n            End If\n        Loop\n\n        objDoc.Close\n        strText = strText &amp; vbCrLf\n    End If\nNext\n\nobjWord.Quit\n\nSet objTextFile = objFSO.CreateTextFile(\"C:\\Scripts\\Test.txt\")\nobjTextFile.Write strText\nobjTextFile.Close\n<\/pre>\n<p>As you can see, we start off by creating an instance of the <b>Scripting.FileSystemObject<\/b>, the COM object we\u2019ll use to retrieve a collection of all the files in the folder C:\\Scripts. Once we create this object we promptly put it to use, using the FileSystemObject and the <b>GetFolder<\/b> method to bind us to the Scripts folder:<\/p>\n<pre class=\"codeSample\">Set objFolder = objFSO.GetFolder(\"C:\\Scripts\")<\/pre>\n<p>Granted, that\u2019s nowhere near as exciting as an operating system that can make grilled cheese sandwiches. But be patient; we aren\u2019t done yet.<\/p>\n<p>At this point we take a slight detour in our code, using these two lines of code to create an instance of the <b>Word.Application<\/b> object and then make that instance of Word visible onscreen:<\/p>\n<pre class=\"codeSample\">Set objWord = CreateObject(\"Word.Application\")\nobjWord.Visible = True\n<\/pre>\n<p>In case you\u2019re wondering, you don\u2019t <i>have<\/i> to make Word visible onscreen; the script works just fine if you have Word run in an invisible window. However, we like to make Word visible during our initial testing, and for two reasons: 1) it helps us verify what \u2013 if anything \u2013 is actually going on when we run the script; and, 2) if anything <i>does<\/i> go wrong we can quickly and easily close each instance of Word. That way we don\u2019t run the risk of having a dozen or so \u201corphaned\u201d copies of Word running in hidden windows and using up system resources.<\/p>\n<p>Next we set up a For Each loop to loop through all the files in the Scripts folder:<\/p>\n<pre class=\"codeSample\">For Each objFile in objFolder.Files\n<\/pre>\n<p>And that\u2019s a good point: we don\u2019t have much use for <i>all<\/i> the files in C:\\Scripts, do we? In fact, all we care about are the Microsoft Word documents, the .DOC files. So how do we separate the wheat (all the .DOC files) from the chaff (everything that <i>isn\u2019t<\/i> a .DOC file)? Well, these two lines of code help:<\/p>\n<pre class=\"codeSample\">strFilePath = objFile.Path \nstrExtension = objFSO.GetExtensionName(strFilePath)\n<\/pre>\n<p>In the first line we\u2019re grabbing the value of the <b>Path<\/b> property and storing it in a variable named strFilePath; as you might expect, the Path property contains the complete path to the file in question. In line 2, we use the <b>GetExtensionName<\/b> property to extract just the file extension (not including the dot) from that file path. Once we\u2019ve done that we can use this line of code to determine whether or not we are working with a .DOC file:<\/p>\n<pre class=\"codeSample\">If strExtension = \"doc\" Then\n<\/pre>\n<p>And what if we <i>aren\u2019t<\/i> working with a .DOC file? That\u2019s fine; in that case we simply go back to the top of the loop and repeat the process with the next file in the collection. On the other hand, if we <i>are<\/i> working with a .DOC file our next step is to grab that file path and append it (and a carriage return-linefeed character, represented by the VBScript constant <b>vbCrLf<\/b>) to a variable named strText:<\/p>\n<pre class=\"codeSample\">strText = strText &amp; strFilePath &amp; vbCrLf\n<\/pre>\n<p>From there we use these two lines of code to open the .DOC and create an instance of Word\u2019s <b>Selection<\/b> object: <\/p>\n<pre class=\"codeSample\">Set objDoc = objWord.Documents.Open(strFilePath)\nSet objSelection = objWord.Selection\n<\/pre>\n<p>Why do we need an instance of Word\u2019s Selection object? Well, as it turns out, the <b>Find<\/b> object (the object use to, well, find things) happens to be a child object of the Selection object. In a minute or so we\u2019re going to use the Find object to search for all the text that uses the Heading 1 style. Before we do that, however, we need to assign values to a few properties of the Find object:<\/p>\n<pre class=\"codeSample\">objSelection.Find.Forward = True\nobjSelection.Find.Format = True\nobjSelection.Find.Style = \"Heading 1\"\n<\/pre>\n<p>Let\u2019s see what we have here. Setting the <b>Forward<\/b> property to True simply tells the script that we want to start searching at the beginning of the document and continue searching until there\u2019s nothing left to search. Setting the <b>Format<\/b> property to True tells the script that we\u2019re searching for a particular type of formatting. And what type of format are we searching for? Why, the Heading 1 style, of course, which explains why we set the <b>Style<\/b> property to <i>Heading 1<\/i>. <\/p>\n<p>That brings us to the following chunk of code:<\/p>\n<pre class=\"codeSample\">Do While True\n    objSelection.Find.Execute\n    If objSelection.Find.Found Then\n        strText = strText &amp; objSelection.Text &amp; vbCrLf\n    Else\n        Exit Do\n    End If\nLoop\n<\/pre>\n<p>As you probably figured out for yourself, this is the block of code where we search for any text that uses the Heading 1 style. (See, that\u2019s why we need to bring you the inside scoop on Windows 7; you guys are more than capable of figuring out the scripting stuff all on your own.) To begin with, we set up a Do loop designed to run as long as True is equal to True. In case you\u2019re wondering, that\u2019s a loop designed to run forever and ever, or at least until we explicitly tell the script to exit the loop. <\/p>\n<p>And you\u2019re right: in this day and age it <i>is<\/i> hard to tell if True is still equal to True, isn\u2019t it?<\/p>\n<p>Inside the loop we call the <b>Execute<\/b> method and search for the first instance of the Heading 1 style. What if we can\u2019t find <i>any<\/i> instance of the Heading 1 style? That\u2019s fine; if the <b>Found<\/b> property comes back False we simply call the <b>Exit Do<\/b> statement and exit our not-so-endless loop:<\/p>\n<pre class=\"codeSample\">Exit Do\n<\/pre>\n<p>If the Found property comes back True we run this line of code instead:<\/p>\n<pre class=\"codeSample\">strText = strText &amp; objSelection.Text &amp; vbCrLf\n<\/pre>\n<p>As you can see, there isn\u2019t anything too-terribly fancy going on here. When you find a chunk of text in Microsoft Word that text automatically becomes selected. That makes it easy to grab the found text (in this case, any text that uses the Heading 1 style): all we have to do is reference the Selection object\u2019s <b>Text<\/b> property. And what are we going to do with that selected text? Nothing much; we\u2019re simply going to append it (and another carriage return-linefeed) to the variable strText. <\/p>\n<p>From there it\u2019s back to the top of the Do loop, where we again call the Execute method and look for the next instance of the Heading 1 style. After we\u2019ve found all the Heading 1 styles in the first document we exit the loop (because the Found property comes back False), then call the <b>Close<\/b> method to dismiss the first Word document. We add a blank line to the end of strText, then hop back to the top of the For Each loop and try again with the next file in the collection.<\/p>\n<p>Wow. That\u2019s like riding a roller coaster, eh?<\/p>\n<p>Eventually we will have searched all the .DOC files in C:\\Scripts. When we\u2019ve reached that point we\u2019re almost done; in fact, all we have to do now is call the <b>Quit<\/b> method to terminate our instance of Microsoft Word, then execute these three lines of code:<\/p>\n<pre class=\"codeSample\">Set objTextFile = objFSO.CreateTextFile(\"C:\\Scripts\\Test.txt\")\nobjTextFile.Write strText\nobjTextFile.Close\n<\/pre>\n<p>This is code you\u2019re probably very familiar with. In the first line, we use the FileSystemObject and the <b>CreateTextFile<\/b> method to create a new text file named C:\\Scripts\\Test.txt. In the second line we use the <b>Write<\/b> method to write the contents of strText to this new file, a file we close in line 3. And what will Test.txt look like after we finish with it? With any luck it should look like this:<\/p>\n<pre class=\"codeSample\">C:\\scripts\\abcd.doc\nThis is a Heading 1 headingSo is thisAnd so is this\n\nC:\\scripts\\test.doc\nHeading 1, No. 1Heading 1, No. 2Heading 1, No. 3\nHeading 1, No. 4\n\nC:\\scripts\\test2.doc\nThis is the only instance of Heading 1 in this file\n<\/pre>\n<p>In other words, we\u2019ve copied all the text styled as Heading 1 from all the Word documents in the folder C:\\Scripts and saved that information to our text file. Which is pretty cool, although we have to admit that it would be even cooler if the script made you a grilled cheese sandwich as well. If you want a grilled cheese sandwich, however, well, you\u2019re just going to have to wait for Windows 7.<\/p>\n<table id=\"EYAAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p><b>Legal disclaimer<\/b>. The Scripting Editor feels it would be a good idea if we mentioned that: 1) Windows 7 is highly unlikely to ever make you a grilled cheese sandwich; 2) there probably won\u2019t be 500 TV channels embedded within Windows 7; and, 3) while there <i>may<\/i> be touch screen capability built into Windows 7 the odds are pretty good that the computer won\u2019t get upset if you actually touch it. \u201cWe need to make that clear to everyone,\u201d she noted. \u201cAfter all, we don\u2019t want to get fired.\u201d<\/p>\n<p>And that\u2019s true, especially with the Scripting Son about to graduate from high school and then head off to college. On the other hand, if people really <i>did<\/i> get fired from Microsoft, well, then why would the Scripting Guy who writes this column still be here?<\/p>\n<p>In other words, don\u2019t give up on those grilled cheese sandwiches, at least not yet.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<table id=\"EMBAC\" 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> The Scripting Editor has been rethinking that whole \u201cgetting fired\u201d thing. It might be nice to have the summer off\u2026. Grilled cheese, anyone?<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I have a folder with scores of Word documents in it. What I need to do is open each document, copy anything that uses the Heading 1 style, and then write that information (the file name and anything that uses the Heading 1 style) to a single text file. Is there a [&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":[84,49,3,5],"class_list":["post-55463","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-microsoft-word","tag-office","tag-scripting-guy","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I have a folder with scores of Word documents in it. What I need to do is open each document, copy anything that uses the Heading 1 style, and then write that information (the file name and anything that uses the Heading 1 style) to a single text file. Is there a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55463","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=55463"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55463\/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=55463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=55463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=55463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}