Hey, Scripting Guy! I have really been enjoying the recent Windows PowerShell articles on the Script Center. I am wondering if it is possible to use Windows PowerShell to work with a Microsoft Office Word document. Specifically, what I would like to be able to do is to change the paragraph formatting and perhaps add a border. I may be asking too much, but I guess I can always hope.
– DP
Hi DP,
I am glad you want to format a paragraph, rather than format say, for instance, your hard disk. If you did format your hard disk, you would not have any more paragraph problems. But then just because you can do something, does not mean you should do something. So maybe you better not format your hard drive—at least not yet.
Rather than opening up the Word document and then selecting the paragraphs and the changing the font size and then highlighting the last sentence and then selecting the border icon, we need to come up with a way to automate this process in Word. In fact, after spending an hour on the treadmill trying to format my stomach, I came up with the FormatWordParagraph.ps1 script. I am still working on the FormatStomach.ps1 script (so far, I have been unable to come up with a good API to use, other than the treadMill API, which, while it works pretty good, is rather difficult to use). Here is the FormatWordParagraph.ps1 script. (By the way, there is a VBScript here that works with Word that might be interesting to look at for comparison. In addition, there are quite a few VBScripts for Microsoft Office in the Script Center Script Repository. You may want to take a look at the Script Repository’s home page as well.)
FormatWordParagraph.ps1
$filePath = “c:\fso\test.doc” $word = New-Object -comobject word.application $word.visible = $true $doc = $word.documents.open($filePath) $paragraphs = $doc.paragraphs $paragraphs.indentFirstLineCharWidth(2) $lineStyle = “microsoft.office.interop.word.wdlLineStyle” -as [type] $colorIndex = “microsoft.office.interop.word.wdColorIndex” -as [type] $lineWidth = “microsoft.office.interop.word.WdLineWidth” -as [type] $borderType = “microsoft.office.interop.word.wdBorderType” -as [type] Foreach($paragraph in $paragraphs) { $paragraph.Range.font.size = 10 } $border = $paragraphs.item(“1”).borders.item($borderType::wdBorderBottom) $border.lineStyle = $lineStyle::wdLineSingle $border.ColorIndex = $colorIndex::wdAuto $border.lineWidth = $lineWidth::wdLineWidth225p $border.visible = $true $doc.save() $word.quit()
Well, DP, this script is about as difficult as falling off a boat with 50 pounds of scuba gear strapped on. After you get your momentum going, it just happens. As they said while I was diving in the Little Caymans two weeks ago, “pool’s open” (not sure why they say that, it must be Caymanian for “get your happy butt off my boat.”) The pool’s open—let’s dive in. But before we do, here’s the Word document we are going to work on:
The first line of code is very simple. We simply assign a string that represents the path to the file we want to open. Remember in Windows PowerShell we use a dollar sign in front of all variables. This makes it easy to know that we are working with a variable. This is seen here:
$filePath = “c:\fso\test.doc”
The next thing we need to do is to create an instance of the word.application object. To do this, we use the New-Object cmdlet and use the -comobject parameter to create the object. We store the returned object in the $word variable as seen here:
$word = New-Object -comobject word.application
When we have a copy of the word.application object, we can use it in many different ways. Here is the documentation on MSDN that discusses this object. Stay tuned for more “Hey, Scripting Guy!” articles using some of these methods.
Now we have a decision to make, DP. Do you want to see what is going on or not? This is not necessarily a rhetorical question. In our script, we are making it visible because it makes for an interesting demo. However, if you want to modify several hundred Word documents, watching the show would be more boring than an old Car 54, Where Are You? rerun. To make the Word document visible, we simply set the visible property to be equal to $true as seen here:
$word.visible = $true
Then we need to open the document:
$doc = $word.documents.open($filePath)
Next we need to get the collection of paragraphs:
$paragraphs = $doc.paragraphs
After we have the paragraphs collection, we indent the first line of each paragraph by two spaces. This is easy to do:
$paragraphs.indentFirstLineCharWidth(2)
Now for something that is very cool with Windows PowerShell. It looks a little bit ugly, but it is very cool nonetheless. We are going to use Word enumeration values for border line style, border color, border width, and border type (but not border collie):
$lineStyle = “microsoft.office.interop.word.wdlLineStyle” -as [type] $colorIndex = “microsoft.office.interop.word.wdColorIndex” -as [type] $lineWidth = “microsoft.office.interop.word.WdLineWidth” -as [type] $borderType = “microsoft.office.interop.word.wdBorderType” -as [type]
What is so cool about being able to use enumeration values? Let’s look at one of the enumerations in Table 1. As you can see in Table 1, Word defines a number of values that are used to control the width of a line that is used for the border. In VBScript, you would typically create a constant and assign the number from the value column, and then use it in the script. In VB.NET or in C#, you would use the enumeration directly. In Windows PowerShell, we can also use the enumeration. For each of the enumeration types we create, we place the name of the type, and then we use the -as operator to tell it we want to use the variable as a particular type. Even though the code may look a little confusing, all we really did was copy the name of the enumeration we found in MSDN, and then assign it to the variable as a type.
Table 1 WdLineWidth Enumeration Values
Name | Value | Description |
wdLineWidth025pt |
2 |
0.25 points |
wdLineWidth050pt |
4 |
0.50 points |
wdLineWidth075pt |
6 |
0.75 points |
wdLineWidth100pt |
8 |
1.00 points (default) |
wdLineWidth150pt |
12 |
1.50 points |
wdLineWidth225pt |
18 |
2.25 points |
wdLineWidth300pt |
24 |
3.00 points |
wdLineWidth450pt |
36 |
4.50 points |
wdLineWidth600pt |
48 |
6.00 points |
Now we want to change the font of our paragraphs. To do this, we use the Foreach statement, because the paragraphs property returns a collection of paragraphs. Just like in VBScript, we need to iterate through the collection, so we use Foreach. We use the variable $paragraph to represent one paragraph out of the collection. The font size is found in the Range.font.size property. We set this value equal to 10. The curly brackets indicate we have a code block. That is, the $paragraph.Range.font.size = 10 code will be repeated once for each paragraph in the collection of paragraphs. This section of code is seen here:
Foreach($paragraph in $paragraphs) { $paragraph.Range.font.size = 10 }
To set the border on the first paragraph, we use the item method from the paragraph collection that is held in the $paragraphs variable. We choose the first paragraph by supplying 1 to the item method. Now we get the borders collection by using the borders property, and again use the item method to retrieve a specific border. The border we want to draw is the bottom border. To do this we use the wdBorderBottom enumeration from the wdBorderType enumeration. We have stored this enumeration type in the variable $borderType. The secret here is the use of the double colon (::) to get our specific enumeration. This line of code is seen here:
$border = $paragraphs.item(“1”).borders.item($borderType::wdBorderBottom)
Next we use the enumerations we created earlier to supply the line style, the color, and the width of the bottom border we will draw. Notice that we use the same syntax, the property of the border, the enumeration, the double colon, and then the actual enumeration name that was taken from MSDN. This section of code is shown here:
$border.lineStyle = $lineStyle::wdLineSingle $border.ColorIndex = $colorIndex::wdAuto $border.lineWidth = $lineWidth::wdLineWidth225p
Now we need to make the border visible. This works exactly the same way it would in VBScript: You set the visible property of the border to true. This is seen here:
$border.visible = $true
Finally, we want to save our changes, and quit Word. To do this we use the save method and the quit method. The only hard part here is that you save the document and you quit the Word application.
Important note: If you make the Word application invisible with $word.visible = $false, and you forget to quit Word, you can end up with multiple instances of winword.exe running on your system. If you are working with hundreds of Word documents…well, let’s just say you probably will not quite make it through hundreds of Word documents before your work station falls off the desk gasping for air and whining about lack of .
$doc.save() $word.quit()
You can see the newly modified Word document here:
So, DP, I hope this helps you with your Word paragraph and border problems. Stay tuned for more Word fun next time. Until then, take care.
Ed Wilson and Craig Liebendorfer, Scripting Guys
Hey Scripting Guy, I have an issue where my shared printer defaults are being overridden by the word defaults. (all other applications are fine, just word). I've read that changing the system locale to UK should automatically set the paper size to A4 (instead of letter), unfortunately, when I click on printer properties (from within word), the page size shows letter, unless I got to Layout, Size, and click on A4. This...