Adding HyperLinks to a Word Document in Powershell

Dustin Morris
4 min readJan 21, 2022

I wanted to troubleshoot a section of code to see if a large file was causing an error that involved a Word document. Perhaps the best way to test the problem was to induce an Out Of Memory failure during the debug process.

However, I wanted to practice Powershell writing skills. So, I wrote a script to make a large file in Word.

Word uses Open XML. Open XML Formats and file name extensions (microsoft.com). In fact, if you change the file extension of a .docx file to .zip and then extract the files, you can see the Open XML files that comprise the entire document.

So how do we edit a Word document and add hyperlinks using Powershell?

First you need to install Open-XML-SDK GitHub — dotnet-campus/Open-XML-SDK: Open XML SDK by Microsoft.

Next, not strictly necessary but useful for my purpose was to generate random long URLs. In this script, I am using the first 5 letters of the English alphabet and randomly adding a letter to a string. Additionally, I am randomly adding a “/” with a 20% chance. I then append an endpoint on the URL, being careful not to include the “/” if it is the last value. This will create a long URL string that is at least 900 characters long.

Get-RandomUrl Code

I then initialize some variables and open the Word document I already created. Add-Type is so I can use the Open-XML-SDK I already installed.

Initialize Variables and open the Word document

I then call my Get-RandomUrl function and check the word documents HyperlinkRelationships for an existing URL. This is a separate file when examining the Open Xml of the word document that contains a list of relationships (relationships.xml.rel). This is where you will find your hyperlink string associated with a hyperlink object in the document.xml. If it already exists, I exit the program.

Verify the Url doesn’t already exist the HyperlinkRelationships

The core of the program follows. I’ll break it down section by section.

Full heart of the program

First, I need to create the hyperlink. But to do that I need pieces that the Hyperlink object is expecting.

The ProofError class isn’t strictly needed. The ProofError class wraps the link to show that a Grammar error maybe present.

Using the ProofError class

The RunStyle class provides a reference to the style to display. I use the “Hyperlink” style which is predefined.

Using the RunStyle class

Next, I create a variable to shorten $ToDoc.MainDocumentPart because I will be using it later on. This is where I add the relationship to the document.xml.rel file. Remember this is where the actual link is stored.

Two other classes are buried in here. The Run class which wraps around text, hyperlinks, paragraphs, etc. to provide logical grouping. And the Text class which is exactly as it sounds.

Finally, all those components are put together to build the Hyperlink class. Additional steps are necessary to link the hyperlink in the Body to the hyperlink in the relationships document. And the History property is set to viewed using the OnOffValue class.

Creating the hyperlink

The next step is to add the hyperlink to the body of the main document. We begin by creating a Paragraph object initialized with the Hyperlink object we just created. I then need to get the type of the paragraph so I can call the GetMethods() method on the Body class. I am using System.Reflection to retrieve the InsertAt<T>() method. There are 2 methods called InsertAt(). One uses generics and the other one doesn’t. So I narrow the selection down from 2 to 1 by using the property ContainsGenericParameters. Counterintuitively, I then must InsertAt a generic method by calling MakeGenericMethod and giving the type I am going to assign the generic <T> which in this case is my Paragraph type. I then Invoke the newly created method on the Body object with the $newParagraph element at an index location of 1.

And then finish off the document by saving and then closing it. $ToDoc.Close()

Saving the hyperlink to the main document

I finished off my program with a while loop so I could get the file size I was trying to create. I will leave that for the reader to deduce.

--

--