Creating a SharePoint page using Microsoft Graph API and Power Automate

Thanks to the workflow that notifies me of updates to the Microsoft Graph API, I saw a new addition to the list: the sitePage resource type.

This is exciting for me, as I currently have some workflows that distribute SharePoint pages to various sites both within our own tenant, as well as client tenants. Currently these are triggered by a page being published in a central location, with specific information used as trigger conditions.

What’s annoying about this scenario is that I need to create connectors in Power Automate to the client tenant using an account in their environment. It also means I need a workflow per client (to keep it clean).

Now with the addition of the sitePage resource type in Microsoft Graph, I can make this work programmatically across any number of clients – all from a single workflow.

WARNING: This is a beta feature at present, so don’t use it for production systems unless you’re find to accept the risks.

Requirements

The requirements of this are fairly simple. We need:

  • An app registration in Azure AD that has the “Sites.ReadWrite.All” application permission added
  • A repository where the details are stored, including:
    • Client name
    • Tenant ID
    • App/Client ID
    • Secret
    • SharePoint site ID

Now, we could use a different way to authenticate, and we could also use an action to perform a search in the tenant to find the relevant site by name or URL, but if we’ve got that – then it’s not exactly difficult to get the SharePoint site ID and store it in our repository.

For the purposes of this, I’m going to store it in a SharePoint list:

 

Workflow

At a high-level, my workflow is quite simple:

 

In my specific scenario, all the workflow is doing is publishing a page with an embedded video, as part of a program of regular content I create for clients. So all I need to provide is a page title and the URL suffix from the embed code.

The next step of the workflow takes my page title, and turns it into a file name:

The code used here is:

concat(replace(triggerBody()['text'],' ','-'),'.aspx')

 

From here, we’re now ready to retrieve all the sites we want to apply this to:

Within our Apply to Each, we have three steps:

  1. Create the page
  2. Parse the JSON of the page creation
  3. Publish the page, using the ID from step 2

(If you’re comfortable with extracting the page ID value directly from the results of step 1, then you don’t need the Parse JSON action.)

In the page creation action, I’m creating a very simple page that only has a single embed web part on it, and I’m passing variables from both the trigger as well as the Get Items action.

 

The Parse JSON is relatively straightforward:

And for the final step we hit publish on the page:

 

And that’s it! We have a simple page published in each tenant listed, with the same content.

If you want something more glamorous, refer to the sitePage resource type page to get a breakdown of the structure of the body of the content.

 

Appendix

Here’s the full details of the body of the page creation and Parse JSON actions.

Create page

{
  "name": "@{outputs('Compose_-_replace_spaces_with_hyphens_and_add_file_extension')}",
  "title": "@{triggerBody()['text']}",
  "pageLayout": "article",
  "promotionKind": "newsPost",
  "showComments": false,
  "showRecommendedPages": false,
  "titleArea": {
    "enableGradientEffect": true,
    "imageWebUrl": "/_layouts/15/images/sleektemplateimagetile.jpg",
    "layout": "plain",
    "showAuthor": false,
    "showPublishedDate": true,
    "showTextBlockAboveTitle": false,
    "textAboveTitle": "",
    "textAlignment": "left",
    "imageSourceType": 2,
    "title": "@{triggerBody()['text']}"
  },
  "canvasLayout": {
    "horizontalSections": [
      {
        "layout": "oneColumn",
        "id": "1",
        "emphasis": "none",
        "columns": [
          {
            "id": "1",
            "webparts": [
              {
                "id": "669d4d75-eca0-4e8b-95d7-2e765dd4859a",
                "webPartType": "490d7c76-1824-45b2-9de3-676421c997fa",
                "data": {
                  "audiences": [],
                  "dataVersion": "1.2",
                  "description": "Embed content from other sites such as Sway, YouTube, Vimeo, and more",
                  "title": "Embed",
                  "properties": {
                    "embedCode": "<iframe src=\"https://player.vimeo.com/video/@{triggerBody()['text_2']}\" width=\"640\" height=\"360\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"\"></iframe>",
                    "cachedEmbedCode": "<iframe src=\"https://player.vimeo.com/video/@{triggerBody()['text_2']}\" width=\"640\" height=\"360\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"\"></iframe>",
                    "shouldScaleWidth": true,
                    "thumbnailUrl": "",
                    "cachedEmbedCodeThumbnail": ""
                  },
                  "serverProcessedContent": {
                    "imageSources": [
                      {
                        "key": "imageSource",
                        "value": "/_LAYOUTS/IMAGES/VISUALTEMPLATEIMAGE1.JPG"
                      }
                    ]
                  }
                }
              }
            ]
          }
        ]
      }
    ]
  }
}

Parse JSON

{
    "type": "object",
    "properties": {
        "@@odata.context": {
            "type": "string"
        },
        "@@odata.etag": {
            "type": "string"
        },
        "eTag": {
            "type": "string"
        },
        "id": {
            "type": "string"
        },
        "lastModifiedDateTime": {
            "type": "string"
        },
        "name": {
            "type": "string"
        },
        "webUrl": {
            "type": "string"
        },
        "title": {
            "type": "string"
        },
        "pageLayout": {
            "type": "string"
        },
        "thumbnailWebUrl": {
            "type": "string"
        },
        "promotionKind": {
            "type": "string"
        },
        "showComments": {
            "type": "boolean"
        },
        "showRecommendedPages": {
            "type": "boolean"
        },
        "createdBy": {
            "type": "object",
            "properties": {
                "user": {
                    "type": "object",
                    "properties": {
                        "displayName": {
                            "type": "string"
                        }
                    }
                }
            }
        },
        "lastModifiedBy": {
            "type": "object",
            "properties": {
                "user": {
                    "type": "object",
                    "properties": {
                        "displayName": {
                            "type": "string"
                        }
                    }
                }
            }
        },
        "parentReference": {
            "type": "object",
            "properties": {
                "siteId": {
                    "type": "string"
                }
            }
        },
        "contentType": {
            "type": "object",
            "properties": {
                "id": {
                    "type": "string"
                },
                "name": {
                    "type": "string"
                }
            }
        },
        "publishingState": {
            "type": "object",
            "properties": {
                "level": {
                    "type": "string"
                },
                "versionId": {
                    "type": "string"
                }
            }
        },
        "reactions": {
            "type": "object",
            "properties": {}
        },
        "titleArea": {
            "type": "object",
            "properties": {
                "enableGradientEffect": {
                    "type": "boolean"
                },
                "imageWebUrl": {
                    "type": "string"
                },
                "layout": {
                    "type": "string"
                },
                "showAuthor": {
                    "type": "boolean"
                },
                "showPublishedDate": {
                    "type": "boolean"
                },
                "showTextBlockAboveTitle": {
                    "type": "boolean"
                },
                "textAboveTitle": {
                    "type": "string"
                },
                "textAlignment": {
                    "type": "string"
                },
                "title": {
                    "type": "string"
                },
                "authors@odata.type": {
                    "type": "string"
                },
                "authors": {
                    "type": "array"
                },
                "authorByline@odata.type": {
                    "type": "string"
                },
                "authorByline": {
                    "type": "array"
                },
                "imageSourceType": {
                    "type": "integer"
                },
                "serverProcessedContent": {
                    "type": "object",
                    "properties": {
                        "imageSources": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "key": {
                                        "type": "string"
                                    },
                                    "value": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "key",
                                    "value"
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}

Also published on Medium.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: