Skip to content

Adds Experimental option to use PnP.Core.Provisioning - #5474

Open
Adam-it wants to merge 5 commits into
pnp:devfrom
Adam-it:adds-experimental-option
Open

Adam-it wants to merge 5 commits into
pnp:devfrom
Adam-it:adds-experimental-option

Conversation

@Adam-it

@Adam-it Adam-it commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

🎯 Aim

The aim is to add - Experimental option provisioning template commands so that when used it will use PnP.Core.Provisioning engine under the hood, and not PnP Framework.

Worth pointing out

Since PnP Core is more MS Graph and SP Rest based, additional scopes are needed than just AllSites.FullControl. So in order to use PnP.Core.Provisioning fully the app reg should have the following
Select Microsoft Graph > Delegated permissions > select Group.ReadWrite.All
Select Microsoft Graph > Delegated permissions > select openid
Select Microsoft Graph > Delegated permissions > select profile
Select Microsoft Graph > Delegated permissions > select Sites.Manage.All
Select Microsoft Graph > Delegated permissions > select User.Read.All
Select SharePoint > Delegated permissions > select AllSites.FullControl
Select SharePoint > Delegated permissions > select AllSites.Manage
Select SharePoint > Delegated permissions > select TermStore.ReadWrite.All
Select SharePoint > Delegated permissions > select User.Read.All

📸 Result

Untitled

@gautamdsheth gautamdsheth self-assigned this Oct 1, 2026
@gautamdsheth

Copy link
Copy Markdown
Collaborator

Thanks @Adam-it! I tested this against a dev tenant, running both engines side by side. The read and extract side works well: a full site extract with -Experimental took 118 s against 212 s with PnP Framework. Export-PnPListToSiteTemplate, Add-PnPDataRowsToSiteTemplate, Add-PnPListFoldersToSiteTemplate, Add/Remove-PnPFileToSiteTemplate, Set-PnPSiteTemplateMetadata, Convert-PnPSiteTemplate and the tenant template .pnp round trip all produce the same output as PnP Framework. A few things need fixing before merge, though.

Must fix

1. Invoke-PnPTenantTemplate no longer accepts the template by position or from the pipeline. This affects scripts that don't use -Experimental.
-Template is now TenantTemplateInstancePipeBind, so binding to it needs a type conversion. [string] Path also takes position 0 and pipeline input, and also needs a conversion, so PowerShell can't pick a parameter set:

$t = Read-PnPTenantTemplate .\tenant.xml
$t | Invoke-PnPTenantTemplate          # AmbiguousParameterSet (works in 3.4.1)
Invoke-PnPTenantTemplate $t            # AmbiguousParameterSet (works in 3.4.1)
Invoke-PnPTenantTemplate -Template $t  # works

In a quick simulation of the binder, adding DefaultParameterSetName = ParameterSet_OBJECT to the [Cmdlet] attribute fixed this, and strings still bound to -Path.

2. .pnp packages don't work across engines, in either direction.

  • A PnP Framework package read with -Experimental fails with Unable to cast object of type 'PnP.Framework.Provisioning.Connectors.OpenXML.Model.PnPManifest' to type 'PnP.Core.Provisioning.Connectors.OpenXML.Model.PnPManifest'.
  • The reverse fails the same way.
  • 3.4.1 can't open a package saved with -Experimental: Could not load file or assembly 'PnP.Core.Provisioning'.

So Invoke-PnPSiteTemplate -Path .\template.pnp -Experimental (example 12) fails for every existing package. The root cause is in PnP.Core.Provisioning: the manifest is XAML with a clr-namespace:…;assembly=… reference, and PnPPackage.cs only rewrites the old OfficeDevPnP.Core namespace, not PnP.Framework. The real fix belongs in PnP Core, plus the reverse in PnP Framework. Until then, could this PR catch the cast error and tell the user what's going on?

3. -ExcludeHandlers doesn't work reliably with -Experimental.
PnP Framework has two page flags, Pages and PageContents, which both become Core's single Pages handler. InvertExcludedHandlers runs before that merge, so excluding one flag is undone by the other:

  • Get-PnPSiteTemplate -ExcludeHandlers PageContents -IncludeAllPages -Experimental still extracts every client-side page. PnP Framework extracts none.
  • Invoke-PnPSiteTemplate -ExcludeHandlers Pages -Experimental still creates or overwrites the template's pages. PnP Framework skips them.

Excluding every handler produces an empty Core handler list. Core treats that as "all handlers" and extracts everything, where PnP Framework extracts nothing.

Suggested fix: map the excludes to Core handlers first, remove them from the full list of Core handlers, and error if nothing is left.

4. Files inside a .pnp aren't found when applying through -Stream or -InputInstance.
-Path pkg.pnp -Experimental works. These two routes fail with The file 'x.txt' is not present in the template's files.:

  • -Stream: CoreProvisioningHelper.LoadSiteTemplatesFromStream never sets template.Connector, so it keeps Core's default FileSystemConnector("."). This also affects -Path https://…/x.pnp and Read-PnPSiteTemplate -Stream -Experimental. The PnP Framework path sets provisioningTemplate.Connector = provider.Connector.
  • -InputInstance: InvokeSiteTemplate.Experimental.cs always replaces the connector with one for the current directory. The PnP Framework path only does that when -ResourceFolder is passed.

Should fix

5. Ctrl+C doesn't stop an -Experimental apply. CoreProvisioningReporter.Run uses Task.Run with no cancellation. I stopped a run 3 s into applying a template with 6 lists. The cmdlet returned after 1.5 s with 0 lists created, then all 6 lists appeared within the next 10 s. PnP Framework waits until the engine stops and creates nothing afterwards. Could you connect a CancellationTokenSource to StopProcessing, or at least wait for the task before returning?

6. Document the extra permissions. The scopes listed in the PR description aren't in the cmdlet docs or the article.

7. CHANGELOG fixes:

Minor

  • Has → HasFlag in the PnP Framework code paths, and the BOM removal in two PipeBinds, are unrelated churn. Behaviour is unchanged.
  • InvokeSiteTemplate.Experimental and SetSiteTemplateMetadata.Experimental copy the provider and connector setup from CoreProvisioningHelper.
  • The release build references PnP.Core.Provisioning 1.18.*-*, and only nightly versions exist on NuGet, so the next stable release would ship a nightly build of it.
  • Engine Error messages are shown as warnings.

FYI: differences in engine output (from PnP.Core.Provisioning, not this PR)

Compared with PnP Framework, a full extract of the same site with -Experimental:

  • leaves out per-list hidden taxonomy note fields and CheckoutUser (39 fields)
  • leaves out site and web features (12)
  • drops several system property bag keys
  • adds 51 SupportedUILanguages
  • adds SHAREPOINT\system as an additional owner

I haven't checked whether these matter when the template is applied.

@Adam-it

Adam-it commented Oct 5, 2026

Copy link
Copy Markdown
Member Author

@gautamdsheth all addressed... at least I hope I didn't miss anything 😁, and ready for another round

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants