In Part 1 we modularized PnP templates into multiple XML files.
In Part 2 we wrapped the process in an Azure Function for automation.
Now we’ll make the system cloud-native by replacing local storage (c:\pnp) with Azure Blob Storage.
Part 3: Storing SharePoint PnP Templates in Azure Blob Storage
In Part 1 we modularized PnP templates into multiple XML files.
In Part 2 we wrapped the process in an Azure Function for automation.
Now we’ll make the system cloud-native by replacing local storage (c:\pnp) with Azure Blob Storage.
1. Why Azure Blob Storage?
- Scalable → store thousands of XML templates without size limits
- Centralized → share templates across environments and teams
- Secure → use SAS tokens, Managed Identity or Key Vault for access control
- Automation → Functions can read/write directly to Blob Storage
2. Setting up Blob Storage
- Create a Storage Account in Azure
- Create a Blob Container (e.g.,
templates) - Generate a connection string or use Managed Identity
3. Updating Code to Use Blob Storage
PnP already supports AzureBlobFileSystemConnector instead of FileSystemConnector.
Example: Export to Blob Storage
using Microsoft.SharePoint.Client;
using PnP.Framework;
using PnP.Framework.Provisioning.Connectors;
using PnP.Framework.Provisioning.ObjectHandlers;
using PnP.Framework.Provisioning.Providers.Xml;
using System;
namespace PnPExportBlob
{
class Program
{
static void Main(string[] args)
{
string siteUrl = "https://yourtenant.sharepoint.com/sites/YourSite";
string user = "user@yourtenant.onmicrosoft.com";
string password = "yourpassword";
// Azure Blob Storage config
string connectionString = "DefaultEndpointsProtocol=https;AccountName=YOURACCOUNT;AccountKey=YOURKEY;EndpointSuffix=core.windows.net";
string containerName = "templates";
using (var ctx = new AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(siteUrl, user, password))
{
var connector = new AzureStorageConnector(connectionString, containerName, "xml");
var creationInfo = new ProvisioningTemplateCreationInformation(ctx.Web)
{
FileConnector = connector,
HandlersToProcess = Handlers.Lists
};
var template = ctx.Web.GetProvisioningTemplate(creationInfo);
var provider = new XMLAzureStorageTemplateProvider(connectionString, containerName, "xml");
provider.SaveAs(template, "List_Projects.xml");
Console.WriteLine("✅ Template exported to Azure Blob Storage.");
}
}
}
}
Example: Import from Blob Storage
using Microsoft.SharePoint.Client;
using PnP.Framework;
using PnP.Framework.Provisioning.Providers.Xml;
using PnP.Framework.Provisioning.Connectors;
namespace PnPImportBlob
{
class Program
{
static void Main(string[] args)
{
string targetUrl = "https://yourtenant.sharepoint.com/sites/TargetSite";
string user = "user@yourtenant.onmicrosoft.com";
string password = "yourpassword";
// Azure Blob Storage config
string connectionString = "DefaultEndpointsProtocol=https;AccountName=YOURACCOUNT;AccountKey=YOURKEY;EndpointSuffix=core.windows.net";
string containerName = "templates";
using (var ctx = new AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(targetUrl, user, password))
{
var provider = new XMLAzureStorageTemplateProvider(connectionString, containerName, "xml");
var template = provider.GetTemplate("List_Projects.xml");
ctx.Web.ApplyProvisioningTemplate(template);
Console.WriteLine("✅ Template imported from Azure Blob Storage.");
}
}
}
}
4. Integrating with Azure Functions
In Part 2 we used:
var provider = new XMLFileSystemTemplateProvider(@"c:\pnp", "");
Now we swap it for:
var provider = new XMLAzureStorageTemplateProvider(connectionString, "templates", "xml");
This means both export and import will save/load templates directly from Blob Storage, so Power Automate (or any system) can also fetch the XMLs later.
5. Best Practices
- Do not hardcode keys → use Azure Key Vault or Managed Identity
- Organize containers → use folder-like prefixes:
/exports/{siteName}/Fields.xml/exports/{siteName}/Lists/List_Projects.xml
- Versioning → enable Blob versioning to keep history of templates
- Lifecycle policies → auto-clean old templates after X days
✅ Key Takeaways
| Step | Local Disk | Cloud Native |
|---|---|---|
| Connector | FileSystemConnector(@"c:\pnp") | AzureStorageConnector(connectionString, container, "xml") |
| Provider | XMLFileSystemTemplateProvider | XMLAzureStorageTemplateProvider |
| Location | c:\pnp\*.xml | https://<account>.blob.core.windows.net/templates/*.xml |
| Benefit | Local only | Globally accessible, secure, automated |
👉 With this change, the provisioning workflow is fully cloud-based:
- Azure Functions orchestrate
- Templates live in Blob Storage
- Power Automate can trigger and even retrieve XMLs
