Weekend Scripter: Add Comment to Word Doc


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 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. I find myself adding exactly the same sort of comments to documents. Here is a sample of comments that I have 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 (you) is excellent for writing how-to topics, but it can break down if you are not careful. The third person (he or she) 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 I 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 on. Sounds like I needed a script.

Add 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 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, 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 Comment and Comment 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 that talks about this: Working with Range Objects.

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.

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 then my comment:

$doc.Comments.Add($range,"This is a great listing of topics")

Close things out and clean stuff up

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()

 As shown here, the comment appears in my Word document when I open it:

 Image of table listing plays, topics, and approaches

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

Comments (8)

  1. jrv says:

    I should also note that this code:
    $doc.Comments.Add($range,"This is a great listing of topics")
    returns an object that has to be released or the application will not shut down.

    $r=$doc.Comments.Add($range,"This is a great listing of topics")

    Now you have something to release.

    This is one of the many ways Office can make life difficult.

  2. mredwilson says:

    PageRank, Thank you for your compliment. You are welcome to share a link to this article but not to reproduce it.

    Ed Wilson
    Microsoft Scripting Guy

  3. jrv says:

    In any larger script that automates an Office program it is likely you will end up with multiple references set on any COM object that you hold. To releases these you will need to call "Release" until the count returns to zero.

    Like this:

    while([System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc)){}

    I also find it advantageous to not create references unless it is very convenient.

    This avoids a reference:

    $doc=$word.documents.open($filePath)
    $doc.Comments.Add($doc.sections.item(1).Range,"This is a safer way to do it")

    The above eliminates interim objects that have to be remembered and released.

  4. pagerank says:

    This article has great reference value, thank you very much for sharing, I would like to reproduced your article, so that more people would see it.

  5. pagerank1 says:

    Thanks for taking the time to discuss this, I feel strongly about it
    and love learning more on this topic. If possible, as you gain
    expertise, would you mind updating your blog with more information? It
    is extremely helpful for me.

  6. pagerank1 says:

    Excellent read, I just passed this onto a colleague who was also looking for it, And he actually bought me lunch because I found it for him. So I should thank you for the free lunch I got.

  7. Search Engine Optimization Service says:

    Technology is the collection of techniques, methods or processes used in the production of goods or services or in the accomplishment of objectives, such as scientific investigation .

  8. sathish ratna says:

    Excellent blog…thanks for sharing such things…its very interesting…
    i’m searching for this information from long time…

Skip to main content