How to post using Confluence REST API HTML Macro in Powershell
Asked by Paul:

Hi, I'm after a little help with an problem. I'm trying to post a html table that is auto generated using code. If I manually add a HTML Macro to the page and paste the HTML code into the section everything works find.  

I can upload the HTML code into a page without the HTML Macro and it works but I don't get the nice style sheet on the data's table which is what I am after.  

I found a same on how to post/update a page with a Confluence-History Macro that works.  

I just can not get the HTML Macro to work via an automated PowerShell script.  

I've attached the code, the 2x bits of code that i mention above are tagged "$HTMLPage".   
Thanks for your help and comments in advance.  

<br />

clear-host  
clear-history

write-host -ForegroundColor Cyan "Requesting Login ID and password to authenticate with confluence."  
if(-not($Credentials))  
{  
$Credentials = Get-Credential  
}

$ConfluenceURL = "<https://confluence.site/rest/api/>"

<br />

# Confluence ID for page.  
$ConfluencePageID = "123456"

<br />

$Headers = @{"Authorization" = "Basic "+\[System.Convert\]::ToBase64String(\[System.Text.Encoding\]::UTF8.GetBytes(($Credentials.UserName+":" \`  
+\[System.Runtime.InteropServices.marshal\]::PtrToStringAuto(\[System.Runtime.InteropServices.marshal\]::SecureStringToBSTR($Credentials.Password)) )))  
"Accept"="application/json"  
"ContentType"="application/json"  
'X-Atlassian-Token' = 'nocheck'  
}

$Call = "content/{0}?expand=version,body.storage,ancestors,space,results,contenttype" -f $ConfluencePageID  

\[Net.ServicePointManager\]::SecurityProtocol = \[Net.SecurityProtocolType\]::Tls12

write-host -ForegroundColor Cyan "Logging into the confluence page that requires updating"  
$CurrentConfluence = Invoke-WebRequest -Method GET -Headers $Headers -Uri ($ConfluenceURL + $Call) -UseBasicParsing \| ConvertFrom-Json

Write-Host -ForegroundColor Cyan "obtaining HTML input data."

**# This one does not work!!**   
$HTMLPage= '\<p\>\<br/\>\</p\>\<ac:structured-macro ac:name="html" ac:schema-version="1" ac:macro-id="4f4cf0b7-23d5-43be-94a4-739407bec55c"\>\<ac:plain-text-body\>\<!\[CDATA\[\<div\>\<ul\>\<li\>\<a href="#Domain1"\>Domain1\</a\>\</li\>\<li\>\<a href="#Domain2"\>Domain2\</a\>\</li\>\<li\>\<a href="#Domain3"\>Domain3\</a\>\</li\>\<li\>\<a href="#Domain4"\>Domain4\</a\>\</li\>\<li\>\<a href="#Domain5"\>Domain5\</a\>\</li\>\</ul\>\</div\>\<br/\>\<div\>\<table\> \<colgroup\>\<col/\>\<col/\>\</colgroup\>\<tr\>\<th\>Domain\</th\>\<th\>System Count\</th\>\</tr\>\<tr\>\<td\>Domain1\</td\>\<td\>653\</td\>\</tr\>\<tr\>\<td\>Domain2\</td\>\<td\>2\</td\>\</tr\>\<tr\>\<td\>Domain3\</td\>\<td\>527\</td\>\</tr\>\<tr\>\<td\>Domain4\</td\>\<td\>2\</td\>\</tr\>\<tr\>\<td\>Domain5\</td\>\<td\>2\</td\>\</tr\>\</table\>\</div\>\<br/\>  
\</ac:plain-text-body\>\</ac:structured-macro\>\]\]\>\</ac:plain-text-body\>\</ac:structured-macro\>'

**# this one works for adding a confluence History anchor**   
#$HtmlPage = '\<p\>History macro test\</p\>\<p\>\<ac:structured-macro ac:name=\\"change-history\\" ac:schema-version=\\"1\\" ac:macro-id=\\"360a0d80-082e-4c82-9ee5-0aac5b72f828\\" /\>\</p\>'

$Body = '{{"type":"{0}","title":"{1}","version":{{"number":"{2}" }},"body":{{"storage":{{"value":"{3}","representation":"storage"}}}}}}' -f $CurrentConfluence.type, $CurrentConfluence.title, $HTMLVersion, $HTMLPage

$Call = "content/$($ConfluencePageID)"

Write-Host -ForegroundColor Yellow "Updated the body contents with new information."  
$Error.Clear()  
read-host "Press ENTER to publish the update..."  
try  
{  
$UpdateConfluence = Invoke-WebRequest -Method Put -Uri ($ConfluenceURL + $Call) -Body $Body -Headers $Headers -ContentType "application/json;" \| convertfrom-json  
Write-Host -ForegroundColor Green "Update published"  
}  
catch  
{  
$Error  
}


Answers:
author: Paul
body: Update:  

I've worked it out. the issue is the syntax/why confluence interprets the the speechmark ( " ) in the Ancester coding. You need to change the speechmark to ( \\" )  

<br />

clear-host  
clear-history

write-host -ForegroundColor Cyan "Requesting Login ID and password to authenticate with confluence."  
if(-not($Credentials))  
{  
$Credentials = Get-Credential  
}

$ConfluenceURL = "<https://confluence.site/rest/api/>"

<br />

# Confluence ID for page.  
$ConfluencePageID = "123456"

<br />

$Headers = @{"Authorization" = "Basic "+\[System.Convert\]::ToBase64String(\[System.Text.Encoding\]::UTF8.GetBytes(($Credentials.UserName+":" \`  
+\[System.Runtime.InteropServices.marshal\]::PtrToStringAuto(\[System.Runtime.InteropServices.marshal\]::SecureStringToBSTR($Credentials.Password)) )))  
"Accept"="application/json"  
"ContentType"="application/json"  
'X-Atlassian-Token' = 'nocheck'  
}

$Call = "content/{0}?expand=version,body.storage,ancestors,space,results,contenttype" -f $ConfluencePageID  

\[Net.ServicePointManager\]::SecurityProtocol = \[Net.SecurityProtocolType\]::Tls12

write-host -ForegroundColor Cyan "Logging into the confluence page that requires updating"  
$CurrentConfluence = Invoke-WebRequest -Method GET -Headers $Headers -Uri ($ConfluenceURL + $Call) -UseBasicParsing \| ConvertFrom-Json

<br />

Write-Host -ForegroundColor Cyan "obtaining HTML input data."

**# This one works now!! Highlighted code change**   
$HTMLPage =++*'\<ac:structured-macro ac:name=\\"html\\" ac:schema-version=\\"1\\" ac:macro-id=\\"74c5d460-d9c1-4259-9489-5ca2cea8314c\\"\>\<ac:plain-text-body\>\<!\[CDATA\[*++ \<div\>\<ul\>\<li\>\<a href="#Domain1"\>Domain1\</a\>\</li\>\<li\>*\<a href="#Domain2"\>* Domain2\</a\>\</li\>\<li\>\<a href="#Domain3"\>Domain3\</a\>\</li\>\<li\>\<a href="#Domain4"\>Domain4\</a\>\</li\>\<li\>\<a href="#Domain5"\>Domain5\</a\>\</li\>\</ul\>\</div\>\<br/\>\<div\>\<table\> \<colgroup\>\<col/\>\<col/\>\</colgroup\>\<tr\>\<th\>Domain\</th\>\<th\>System Count\</th\>\</tr\>\<tr\>\<td\>Domain1\</td\>\<td\>653\</td\>\</tr\>\<tr\>\<td\>Domain2\</td\>\<td\>2\</td\>\</tr\>\<tr\>\<td\>Domain3\</td\>\<td\>527\</td\>\</tr\>\<tr\>\<td\>Domain4\</td\>\<td\>2\</td\>\</tr\>\<tr\>\<td\>Domain5\</td\>\<td\>2\</td\>\</tr\>\</table\>\</div\>\<br/\>*++\]\]\>\</ac:plain-text-body\>\</ac:structured-macro\>'++*

$Body = '{{"type":"{0}","title":"{1}","version":{{"number":"{2}" }},"body":{{"storage":{{"value":"{3}","representation":"storage"}}}}}}' -f $CurrentConfluence.type, $CurrentConfluence.title, $HTMLVersion, $HTMLPage

$Call = "content/$($ConfluencePageID)"

Write-Host -ForegroundColor Yellow "Updated the body contents with new information."  
$Error.Clear()  
read-host "Press ENTER to publish the update..."  
try  
{  
$UpdateConfluence = Invoke-WebRequest -Method Put -Uri ($ConfluenceURL + $Call) -Body $Body -Headers $Headers -ContentType "application/json;" \| convertfrom-json  
Write-Host -ForegroundColor Green "Update published"  
}  
catch  
{  
$Error  
}

Results.  
![Capture.PNG](https://community.atlassian.com/t5/image/serverpage/image-id/187143iDCCFD9D2F2F1F45C/image-size/large?v=v2&px=999 "Capture.PNG")

a HTML macro now inserted, with a html code body.

![Capture1.PNG](https://community.atlassian.com/t5/image/serverpage/image-id/187144iD64C764F57621104/image-size/large?v=v2&px=999 "Capture1.PNG")

comments: author: Paulo Santos
body: This is exactly what I needed and I couldn't find it anywhere else. Many thanks!


author: Paul
body: You are welcome,  
I struggled to find any information when I tried to search for this process.  


author: Paulo Santos
body: I also just now realise how easy it can be to find the "format" of other (any?) macros. You can just manually create the page with the macros you like, and "get" the page body from confluence using the api. something like this:

```
result = confluence.get_page_by_id(page_id, expand='body.storage', status=None, version=None)
```

The result variable is now carrying the HTML code in

```
result['body']['storage']['value']
```

and it looks like this:

```
<p class="auto-cursor-target"><br /></p>
<ac:structured-macro ac:name="info" ac:schema-version="1" ac:macro-id="c92de1bf-6219-4e53-9e07-f8add638daca">
<ac:rich-text-body>
<p>Page generated automatically</p>
</ac:rich-text-body>
</ac:structured-macro>
<p class="auto-cursor-target"><br /></p>
<p class="auto-cursor-target">in between text</p>
<p class="auto-cursor-target"><br /></p>
<ac:structured-macro ac:name="html" ac:schema-version="1" ac:macro-id="04fe5d81-5f3e-4de5-b3cf-976217bd5025">
<ac:plain-text-body>
<![CDATA[<!DOCTYPE html>
this is html text]]>
</ac:plain-text-body>
</ac:structured-macro>
<p><br /></p>
<p><br /></p>
<p>lala</p>
<p class="enh-settings hidden" style="display: none;">{}</p>
```

with code highlighting is becomes clear:

![Annotation 2022-06-22 141858.png](https://community.atlassian.com/t5/image/serverpage/image-id/202906i62419EE9E504DD9F/image-size/large?v=v2&px=999 "Annotation 2022-06-22 141858.png")

Maybe this helps someone else too ?


Tags: server