{"id":50743,"date":"2010-04-06T00:01:00","date_gmt":"2010-04-06T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2010\/04\/06\/hey-scripting-guy-how-can-i-add-custom-properties-to-a-microsoft-word-document\/"},"modified":"2010-04-06T00:01:00","modified_gmt":"2010-04-06T00:01:00","slug":"hey-scripting-guy-how-can-i-add-custom-properties-to-a-microsoft-word-document","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-add-custom-properties-to-a-microsoft-word-document\/","title":{"rendered":"Hey, Scripting Guy! How Can I Add Custom Properties to a Microsoft Word Document?"},"content":{"rendered":"<p><a class=\"addthis_button\" href=\"http:\/\/www.addthis.com\/bookmark.php?v=250&amp;pub=scriptingguys\"><img decoding=\"async\" alt=\"Bookmark and Share\" src=\"http:\/\/s7.addthis.com\/static\/btn\/v2\/lg-share-en.gif\" width=\"125\" height=\"16\"><\/a><\/p>\n<p>&nbsp;\n<img decoding=\"async\" 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 class=\"MsoNormal\">Hey, Scripting Guy! A few months ago, you wrote a really cool Hey, Scripting Guy! post, <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2009\/12\/30\/hey-scripting-guy-december-30-2009.aspx\"><font face=\"Segoe\">How Can I Retrieve the Custom Properties of a Microsoft Word Document<\/font><\/a>. The post illustrated how to use Windows PowerShell to read the custom properties from Microsoft Word documents. You, however, did not show how to modify the value of custom properties. I am wondering if you would care to tackle that task now?<\/p>\n<p class=\"MsoNormal\">&#8212; JB<\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\"><img decoding=\"async\" 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\">Hello JB, <\/p>\n<p class=\"MsoNormal\">Microsoft Scripting Guy Ed Wilson here. I am sipping a cup of English Breakfast tea with a little lemon grass and a stick of cinnamon in it. I was able to score some Tim Tams from my friend Brent in Sydney recently while he was in the United States for the Microsoft TechReady conference in Seattle, Washington, so things are progressing nicely this morning. I have <a href=\"http:\/\/en.wikipedia.org\/wiki\/Cream_(band)\"><font face=\"Segoe\">Cream<\/font><\/a> cranked up so loud on my <a href=\"http:\/\/www.zune.net\/en-us\/products\/zunehd\/default.htm\"><font face=\"Segoe\">Zune HD<\/font><\/a> that I can feel the energetic <a href=\"http:\/\/en.wikipedia.org\/wiki\/Jack_Bruce\"><font face=\"Segoe\">Jack Bruce<\/font><\/a> bass licks deep inside my bones, and therefore I am sipping, munching, and grooving as I review the e-mail sent to the <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\"><font face=\"Segoe\">scripter@microsoft.com<\/font><\/a> address. I have no idea where the Scripting Wife is right now. She evacuated the upstairs about the time that <a href=\"http:\/\/en.wikipedia.org\/wiki\/Sunshine_of_Your_Love\"><font face=\"Segoe\">Sunshine of Your Love<\/font><\/a> came on, and she was long gone by the time <a href=\"http:\/\/en.wikipedia.org\/wiki\/Badge_(song)\"><font face=\"Segoe\">Badge<\/font><\/a> was playing. She took her laptop with her and muttered something about me being &ldquo;impossible at times&rdquo;&mdash;as if she weren&rsquo;t alive in the 1970s or something. <\/p>\n<p class=\"MsoNormal\">Anyway, as I was reviewing the e-mail inbox, I ran across Jit&rsquo;s message. I knew it was Jit because I recognized his e-mail address. I first met Jit several years ago in <a href=\"http:\/\/en.wikipedia.org\/wiki\/Brisbane\"><font face=\"Segoe\">Brisbane, Australia<\/font><\/a>, when I went there to teach a VBScript class that was based upon <a href=\"http:\/\/technet.microsoft.com\/en-us\/scriptcenter\/dd793612.aspx\"><font face=\"Segoe\">one of my VBScript books<\/font><\/a>. He was the Microsoft guy that I was to train to deliver my class and I got to work with him for two weeks&mdash;one week in Brisbane and one in Sydney. We have since become great friends. Thinking of Jit reminded me of some of the pictures I took during that trip, such as the following one that was taken in downtown Brisbane. <\/p>\n<p class=\"Fig-Graphic\"><img decoding=\"async\" title=\"Photo Ed took in Brisbane, Australia\" alt=\"Photo Ed took in Brisbane, Australia\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/april\/hey0406\/hsg-04-06-10-01.jpg\" width=\"600\" height=\"450\"><\/p>\n<p class=\"Fig-Graphic\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\">JB, I decided to write the Set-WordCustomProperties.ps1 script for you to allow you to set custom properties on a Microsoft Word document. You should <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2009\/12\/30\/hey-scripting-guy-december-30-2009.aspx\"><font face=\"Segoe\">refer to the Hey, Scripting Guy! post<\/font><\/a> you mentioned in your e-mail message for information about working with custom properties in Microsoft Word, as well as for additional information about working with the <b>InvokeMember<\/b> method. The complete Set-WordCustomProperties.ps1 script is seen here. <\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>Set-WordCustomProperties.ps1<\/p>\n<p><\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">$path = &#8220;C:fsoTest.docx&#8221;<br \/>$application = New-Object -ComObject word.application<br \/>$application.Visible = $false<br \/>$document = $application.documents.open($path)<br \/>$binding = &#8220;System.Reflection.BindingFlags&#8221; -as [type]<\/p>\n<p>$customProperties = $document.CustomDocumentProperties<br \/>$typeCustomProperties = $customProperties.GetType()<\/p>\n<p>$CustomProperty = &#8220;Client&#8221;<br \/>$Value = &#8220;My_WayCool_Client&#8221;<br \/>[array]$arrayArgs = $CustomProperty,$false, 4, $Value<\/p>\n<p>Try<br \/><span>&nbsp;<\/span>{<br \/><span>&nbsp; <\/span>$typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;add&#8221;, $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>out-null<br \/><span>&nbsp;<\/span>}<br \/>Catch [system.exception]<br \/><span>&nbsp;<\/span>{<br \/><span>&nbsp; <\/span>$propertyObject = $typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;Item&#8221;, $binding::GetProperty,$null,$customProperties,$CustomProperty)<br \/><span>&nbsp; <\/span>$typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;Delete&#8221;, $binding::InvokeMethod,$null,$propertyObject,$null)<br \/><span>&nbsp; <\/span>$typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;add&#8221;, $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>Out-Null<br \/><span>&nbsp;<\/span>}<br \/><span>&nbsp;<\/span><br \/>$document.Saved = $false<br \/>$document.save()<br \/>$application.quit()<br \/>$application = $null<br \/>[gc]::collect()<br \/>[gc]::WaitForPendingFinalizers()<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\">JB, the first thing to do is to assign the path to the document. In reality, this could be a <b>Get-ChildItem<\/b> cmdlet that filters all of the document files, in the same manner that was used in <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2010\/04\/05\/hey-scripting-guy-april-5-2010.aspx\"><span>yesterday&rsquo;s Excel article<\/span><\/a>. The reason I left that part out of the script is that the script was already rather complicated, and I did not want to clutter it up anymore than it already was:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$path = &#8220;C:fsoTest.docx&#8221;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">When working with Microsoft Word, it is generally a requirement to create an instance of the <b>Word.Application<\/b> COM object. When the <b>Word.Application<\/b> object is stored in the <b>$application<\/b> variable, the <b>visible<\/b> property is set to <b>false<\/b> to keep the Word document from displaying on the screen. This is shown here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$application = New-Object -ComObject word.application<br \/>$application.Visible = $false<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">It is time to open the Microsoft Word document, and to store the returned <b>Document<\/b> object in the <b>$document<\/b> variable. This is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$document = $application.documents.open($path)<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Because of the way that the COM interop works, the <b>BindingFlags<\/b> class from the <b>System.Reflection<\/b> namespace needs to be created as a type. This is stored in the <b>$binding<\/b> variable as shown here. The <b>BindingFlags<\/b> class will be used several times in the Set-WordCustomProperties.ps1 script:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$binding = &#8220;System.Reflection.BindingFlags&#8221; -as [type]<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Obtain the <b>CustomDocumentProperties<\/b> collection by calling the <b>CustomDocumentProperties<\/b> property. The object is stored in the <b>$customProperties<\/b> variable:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$customProperties = $document.CustomDocumentProperties<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">It is time to retrieve the <b>CustomDocumentProperties<\/b> type by using the <b>GetType<\/b> method. The <b>CustomDocumentProperties<\/b> type is stored in the <b>$typeCustomProperties<\/b> variable. This type will be used later on in the script:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$typeCustomProperties = $customProperties.GetType()<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Next, an array with the custom property name and the value of the custom property is created. The <b>$arrayArgs<\/b> variable stores this information. When creating a custom document property, the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa141979(office.10).aspx\"><font face=\"Segoe\">add method<\/font><\/a> requires four or five different values. The first is the name of the property, and the second specifies whether the property is linked to the contents of the document. If this is set to <b>$true<\/b>, the <b>LinkSource<\/b> value must also be specified. If instead it is <b>$false<\/b>, you must specify the value for the property. The third position is a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa432509(v=office.12).aspx\"><font face=\"Segoe\">MsoDocProperties<\/font><\/a> constant value. Rather than creating the actual enumeration, I used the direct value of 4, which is a <b>msoPropertyTypeString<\/b> value. The following table lists the <b>MsoDocProperties<\/b> enumerations and the enumeration values.<\/p>\n<p class=\"MsoNormal\">  <\/p>\n<table class=\"MsoTableGrid\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"206\">\n<p class=\"MsoNormal\"><b>Name<\/p>\n<p><\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"106\">\n<p class=\"MsoNormal\"><b>Value <\/p>\n<p><\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"204\">\n<p class=\"MsoNormal\"><b>Description<\/p>\n<p><\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"206\">\n<p class=\"MsoNormal\">msoPropertyTypeBoolean<\/p>\n<\/td>\n<td valign=\"top\" width=\"106\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\" width=\"204\">\n<p class=\"MsoNormal\">Boolean value<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"206\">\n<p class=\"MsoNormal\">msoPropertyTypeDate<\/p>\n<\/td>\n<td valign=\"top\" width=\"106\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\" width=\"204\">\n<p class=\"MsoNormal\">Date value<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"206\">\n<p class=\"MsoNormal\">msoPropertyTypeFloat<\/p>\n<\/td>\n<td valign=\"top\" width=\"106\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\" width=\"204\">\n<p class=\"MsoNormal\">Floating point value<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"206\">\n<p class=\"MsoNormal\">msoPropertyTypeNumber<\/p>\n<\/td>\n<td valign=\"top\" width=\"106\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\" width=\"204\">\n<p class=\"MsoNormal\">Integer value<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"206\">\n<p class=\"MsoNormal\">msoPropertyTypeString<\/p>\n<\/td>\n<td valign=\"top\" width=\"106\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\" width=\"204\">\n<p class=\"MsoNormal\">String value<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The <b>LinkSource<\/b>, in the fifth position, would point to the source of the linked property if the <b>LinkToContent<\/b> position was equal to <b>$true<\/b>. This section of the script is shown here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$CustomProperty = &#8220;Client&#8221;<br \/>$Value = &#8220;My_WayCool_Client&#8221;<br \/>[array]$arrayArgs = $CustomProperty,$false, 4, $Value<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">If the custom document property already exists and an attempt is made to write to the property, an error will be generated. To prevent the error from occurring, use the <b>Try\/Catch<\/b> construction. In the <b>Try<\/b> block, the <b>InvokeMember<\/b> method from the <b>CustomDocumentProperties<\/b> type is used to add the property to the <b>CustomDocumentProperties<\/b> collection. If the custom property does not exist, no error is generated, and the property will be added to <b>CustomDocumentProperties<\/b> collection. Following the <b>Add<\/b> method, the <b>InvokeMethod<\/b> static property is used from the <b>Binding Flags<\/b> type. The <b>CustomDocumentProperties<\/b> object is passed, as well as the array containing the information required by the <b>add<\/b> method. This is rather complicated and is a requirement because of the way the COM interop model works. The returned <b>system.object<\/b> is piped to the <b>Out-Null<\/b> cmdlet to keep from cluttering up the Windows PowerShell console. The <b>Try<\/b> section of the script is shown here. The line continuation character (<b>`<\/b>) is used to allow the code block to display properly on our Web page. Normally I would type the <b>InvokeMember<\/b> command on a single line. <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Try<br \/><span>&nbsp;<\/span>{<br \/><span>&nbsp; <\/span>$typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;add&#8221;, $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>out-null<br \/><span>&nbsp;<\/span>}<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">If the custom property already exists and an error is generated, control of the script moves to the <b>Catch<\/b> block. The first thing that must be done inside the <b>Catch<\/b> block is to retrieve the specific <b>CustomDocumentProperty <\/b>object that caused the error and store it in the <b>$propertyObject<\/b> variable. To do this, the <b>InvokeMember<\/b> method is once again called. This time, the <b>Item<\/b> method is used, and the <b>GetProperty<\/b> binding flag is specified. After the specific <b>CustomDocumentProperty<\/b> object has been retrieved, the <b>InvokeMember<\/b> method is called, and this time the <b>Delete<\/b> method is specified. The <b>InvokeMethod<\/b> binding is used along with the <b>CustomDocumentProperty<\/b> object that was stored in the <b>$propertyObject<\/b> variable. This section of the script is shown here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Catch [system.exception]<br \/><span>&nbsp;<\/span>{<br \/><span>&nbsp; <\/span>$propertyObject = $typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;Item&#8221;, $binding::GetProperty,$null,$customProperties,$CustomProperty)<br \/><span>&nbsp; <\/span>$typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;Delete&#8221;, $binding::InvokeMethod,$null,$propertyObject,$null)<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">After the previous Custom Document Property has been deleted, the new value for the Custom Document Property can be added. This code is exactly the same that was used in the initial <b>Try<\/b> block:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp; <\/span>$typeCustomProperties.InvokeMember(`<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>&#8220;add&#8221;, $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>Out-Null<br \/><span>&nbsp;<\/span>}<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">When a <b>Custom Document<\/b> property is added via the Word automation model, the <b>Document<\/b> object <b>saved<\/b> property is not toggled. Therefore, calling the <b>Save<\/b> method from the <b>Document<\/b> object does not save the newly added <b>Custom Document<\/b> property. This behavior is by design. Therefore, to be able to save the newly created <b>Custom Document<\/b> property, it is necessary to first set the <b>saved<\/b> property of the <b>Document<\/b> object to <b>$false<\/b>, and then call the <b>Save<\/b> method from the <b>Document<\/b> object. <\/p>\n<p class=\"Readeraidonly\"><a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2010\/04\/05\/hey-scripting-guy-april-5-2010.aspx\">Yesterday<\/a>, we toggled the <b>Saved<\/b> property of the Excel <b>Workbook<\/b> object to prevent the <b>Save<\/b> dialog box from appearing when we were retrieving linked worksheets.<\/p>\n<p class=\"MsoNormal\">This is shown here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$document.Saved = $false<br \/>$document.save()<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">After all the custom properties have been added, it is time to call the <b>quit<\/b> method from the Word<b> Application<\/b> object. It would also be a good idea to call garbage collection to force removal of the COM objects from memory. This technique was also discussed in yesterday&rsquo;s Hey, Scripting Guy! post. This section of the code is shown here:<\/p>\n<p class=\"CodeBlock\"><span style=\"FO\"><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey, Scripting Guy! A few months ago, you wrote a really cool Hey, Scripting Guy! post, How Can I Retrieve the Custom Properties of a Microsoft Word Document. The post illustrated how to use Windows PowerShell to read the custom properties from Microsoft Word documents. You, however, did not show how to modify the [&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,45],"class_list":["post-50743","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-microsoft-word","tag-office","tag-scripting-guy","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey, Scripting Guy! A few months ago, you wrote a really cool Hey, Scripting Guy! post, How Can I Retrieve the Custom Properties of a Microsoft Word Document. The post illustrated how to use Windows PowerShell to read the custom properties from Microsoft Word documents. You, however, did not show how to modify the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/50743","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=50743"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/50743\/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=50743"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=50743"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=50743"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}