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.


Discover more from Loryan Strant, Microsoft 365 MVP

Subscribe to get the latest posts sent to your email.

Leave a Reply

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

Discover more from Loryan Strant, Microsoft 365 MVP

Subscribe now to keep reading and get access to the full archive.

Continue reading