Table of Contents

Test-PnPSiteTemplate

SYNOPSIS

Validates a PnP site template without applying it.

SYNTAX

By Path

Test-PnPSiteTemplate [-Path] <String> [-TemplateId <String>]
 [-TemplateProviderExtensions <ITemplateProviderExtension[]>]

By Stream

Test-PnPSiteTemplate [-Stream] <Stream> [-TemplateId <String>]
 [-TemplateProviderExtensions <ITemplateProviderExtension[]>]

By XML

Test-PnPSiteTemplate [-Xml] <String> [-TemplateProviderExtensions <ITemplateProviderExtension[]>]

By Template

Test-PnPSiteTemplate [-Template] <ProvisioningTemplate>

DESCRIPTION

Validates a PnP site template without applying it and without making a request to SharePoint. Use it to catch structural problems in a template, for example in a pull request or a release pipeline, before it ever reaches a site.

One result is returned per template found in the source. Every finding is a structured issue carrying a Code, Severity, Message and Location, at one of three severities.

Severity Meaning
Error The template is broken and should not be applied, for example a duplicate identifier, an unreadable package, an unsupported schema, or a referenced file that is not present. This is the only severity that sets IsValid to $false.
Warning The template can be applied but may not behave as intended, for example an older provisioning schema, or an attribute that has been removed from the latest schema.
Information Something the target site or term store has to provide, or something that could not be checked in advance. Out of the box content types and site columns are never declared inside a template, so these appear on almost every template and are grouped into a single issue per location.

How much can be checked depends on what the source provides, which the result states explicitly rather than leaving you to guess.

Property Meaning
IsValid $false only when an Error severity issue was found.
ResourcesChecked $true when the template carried a file connector, so referenced files, localizations, directories, data row attachments, workflow definitions, publishing design packages, document set default documents, app packages, site scripts and relative site logos could be resolved. $false for an in-memory template without a connector, meaning none of those were looked at.
SchemaChecked $true when the source XML was available, so the schema version and removed-element checks could run. $false for a template received through the pipeline.
SchemaVersion The provisioning schema namespace found in the source, when available.

The provisioning schema versions 2019/03 through 2022/09 are recognised. Anything else is reported as an UnsupportedSchema error, because the provisioning engine falls back to the latest deserializer for a namespace it does not know, which quietly produces an empty template rather than failing.

Server relative paths and absolute URLs are resolved at the moment the template is applied, so they are not looked for among the template's own files. A path counts as tokenized when it starts with a token or names a parameter, and one that cannot be found is then reported as UnverifiedResourcePath at Information severity rather than as missing, because only the target site can expand it. A source that merely contains _api or a brace in a folder name is checked normally.

A resource reference that is present but empty is an error in its own right, because the provisioning engine reads every one of them without checking first. This includes a design package or a document set default document whose source path is blank, which is what Get-PnPSiteTemplate produces for default documents when it runs without -PersistBrandingFiles.

XInclude references are resolved before anything else, so a template that lives in an included fragment is validated and can be selected with -TemplateId like any other. Each href is read from the root of the source, matching how the provisioning engine resolves it, and a fragment pulled in by an include is not validated a second time on its own.

When the source is a package, templates stored in a folder inside it are validated as well as those at its root, and an issue in one member names that member in its Location. Passing -TemplateId reports only the issues belonging to the template that was asked for.

The cmdlet never compares the template against a site, so it cannot confirm whether the content types, fields, term sets or hub sites it reports as dependencies actually exist there.

EXAMPLES

EXAMPLE 1

Test-PnPSiteTemplate -Path ./template.pnp

Validates every template found in a PnP site template package and returns one validation result for each template.

EXAMPLE 2

Read-PnPSiteTemplate -Path ./template.xml | Test-PnPSiteTemplate

Validates an in-memory provisioning template received through the pipeline. SchemaChecked is $false on the result because the source XML is no longer available, so the schema version and removed-element checks are skipped.

EXAMPLE 3

$result = Test-PnPSiteTemplate -Path ./template.xml
if ($result | Where-Object { -not $_.IsValid }) {
    $result.Issues | Format-Table Code, Severity, Location, Message
    throw "The site template is invalid."
}

Stops a script when the template contains an error-severity validation issue. Use Where-Object rather than $result.IsValid, because a source holding several templates returns one result for each.

EXAMPLE 4

Test-PnPSiteTemplate -Path ./template.pnp |
    Select-Object -ExpandProperty Issues |
    Where-Object Severity -ne Information |
    Format-Table Severity, Code, Location, Message

Shows only the errors and warnings, hiding the informational dependencies that a template is expected to have on its target site.

EXAMPLE 5

Test-PnPSiteTemplate -Path ./templates.pnp -TemplateId TeamSite

Validates only the template with ID TeamSite from a package containing multiple templates.

PARAMETERS

-Path

Path to an XML site template or a PnP site template package.

Type: String
Parameter Sets: By Path

Required: True
Position: 0
Default value: None
Aliases: None
Accept pipeline input: False
Accept wildcard characters: False

-Stream

Stream containing an XML site template or a PnP site template package.

Type: Stream
Parameter Sets: By Stream

Required: True
Position: 0
Default value: None
Aliases: None
Accept pipeline input: False
Accept wildcard characters: False

-Template

In-memory provisioning template to validate.

Type: ProvisioningTemplate
Parameter Sets: By Template

Required: True
Position: 0
Default value: None
Aliases: None
Accept pipeline input: True (ByValue)
Accept wildcard characters: False

-TemplateId

ID of the template to validate when an XML file or package contains multiple templates.

Type: String
Parameter Sets: By Path, By Stream

Required: False
Position: Named
Default value: None
Aliases: None
Accept pipeline input: False
Accept wildcard characters: False

-TemplateProviderExtensions

Template provider extensions to execute while loading the template.

Type: ITemplateProviderExtension[]
Parameter Sets: By Path, By Stream, By XML

Required: False
Position: Named
Default value: None
Aliases: None
Accept pipeline input: False
Accept wildcard characters: False

-Xml

XML text containing a provisioning template.

Type: String
Parameter Sets: By XML

Required: True
Position: 0
Default value: None
Aliases: None
Accept pipeline input: False
Accept wildcard characters: False

Read-PnPSiteTemplate

Invoke-PnPSiteTemplate

Microsoft 365 Patterns and Practices