Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to add a comment to a Microsoft Word document.
Microsoft Scripting Guy, Ed Wilson, is here. I spend a lot of time using Microsoft Word. In fact, I spend more time using Word than using Microsoft Outlook—and that is saying something—actually, it is saying a lot. Word is open on my computer nearly every day of the year, and from time to time, at all hours of the day. Because I deal with editors, I also have to read comments that they add to Word documents. On the other hand, when I provide peer review for other writers, I also have to be able to add comments to Word documents. From time to time, I find myself adding exactly the same sort of comments to documents. Here is a sampling of comments that I added to over a dozen documents in the last few months:
“Remember, when writing, it is more important to show something, and not to merely tell about something. In technical writing, this can take the form of a table, a line drawing, or an image showing the GUI.”
“Please don’t mix point of views. Remember, first person can be great for a blog, if you are the main writer. The first person "I" brings the reader into your world, and permits you great flexibility when discussing issues that might arise. The second person is excellent for writing how-to topics, but can break down if you are not careful. The third person tends to add a layer of distance that you might not want to have. The most important thing is consistency.”
“When discussing technical matters, variety of word choice is not necessarily a good thing. Don’t substitute program for process, executable for service, app for application, or storage for hard disk drive. It will confuse the reader who knows the difference, and it will be meaningless for a reader who does not.”
In fact, for the documents I was reviewing, I ended up copying the comments into Notepad, and then just used Cut and Paste. For each comment, I had to make over a dozen keystrokes: switch to Notepad, select a paragraph, copy the paragraph, switch back to Word, find my spot, paste the comment, and so forth and so on. Sounds like I needed a script.
Adding a comment to a Word document … it’s easy
After I decided that I wanted to write a Windows PowerShell script to add a comment to a Word document, I needed to see if it was even possible. I mean, in all the years I have been using Word, and in all the years I have been using Windows PowerShell, I only just now had the need to automate adding comments. But could I do it?
When I have such an idea, I always pop over to MSDN, the Microsoft Developer Network, and look at the Word Object Model Reference documentation for automation. Because it seems there is a new version of Word nearly every year, I always have to ensure that I have the documentation for the version of Word that I am using.
Luckily, I always have the latest version. The object model changes, sometimes in subtle ways, so I always like to look things up. Here is a link to the Object Model Reference (Word 2013 Developer Reference) documentation. I can’t say how long the Comments object has been available, because, like I said, this is the first time I decided to write such a script. I scroll down the list of objects until I see the Comment and the Comments objects. Luckily, the names of the objects make sense. Because I understand the Word object model, I know that a comment will come from a Comments collection. I know that there will be an Add method to add the comment, and I know that such a comment will be attached to a Range object. A Range object specifies a location in a Word document. I can create a specific Range, or I can retrieve a Range object via the Range property from a Document, Section, Paragraph,or other such object. There is a pretty good article on MSDN, Working with Range Objects, that talks about this.
Adding a comment is as simple as calling the Add method from the Comments object, and specifying the Range and the comment text itself. Everything else about it is standard Word automation.
First, the basic Word automation stuff
The first thing I do is specify the path to the file that will receive my comments. In this example, I use the Word document that I created yesterday that holds my Shakespeare research topics. Next, I create the Word.Application object, set the application to not visible, open my Word document, retrieve the first section, and the range that is associated with this section. This code is shown here:
$filePath = "C:\lit\ResearchTopics.docx"
$word = New-Object -comobject word.application
$word.visible = $false
$doc = $word.documents.open($filePath)
$section = $doc.sections.item(1)
$range = $section.Range
Add the comment
After I have my Range object, from the first section of the Word document, and the Comments object, from the Comments property of the document I opened, I can add the comment to the document. It actually makes sense. I am adding a comment to a specific location in a specific document. To specify that location, I need to supply a Range object, from the $range variable, and my comment. Here is the code:
$doc.Comments.Add($range,"This is a great listing of topics")
Close things out and clean stuff up
Now I want to save my changes to the document, close the document, and exit the Word application. I then release all the objects, remove the variables, and call garbage collection to free up the memory. This code is pretty standard for most of my Word automation projects, and it is shown here:
$doc.save()
$doc.close()
$word.quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($range) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Section) | Out-Null
Remove-Variable Doc,Word, range, section
[gc]::collect()
[gc]::WaitForPendingFinalizers()
The complete script is shown here:
$filePath = "C:\lit\ResearchTopics.docx"
$word = New-Object -comobject word.application
$word.visible = $false
$doc = $word.documents.open($filePath)
$section = $doc.sections.item(1)
$range = $section.Range
$doc.Comments.Add($range,"This is a great listing of topics")
$doc.save()
$doc.close()
$word.quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($range) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Section) | Out-Null
Remove-Variable Doc,Word, range, section
[gc]::collect()
[gc]::WaitForPendingFinalizers()
The comment appears in my Word document when I open it. It is shown here:
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy