Dynamischer Einsatz der PnP Remote Provisioning Engine

PnP Remote Provisioning Engine

Die PnP Remote Provisioning Engine, entwickelt im Rahmen der Office Dev Patterns and Practices (PnP) Initiative, ist eine Open-Source-Bereitstellungs-Engine für SharePoint. Die Engine kann verwendet werden, um Anpassungen und Assets von, respektive zu, SharePoint-Websites aus der Ferne zu extrahieren oder anzuwenden. Sie lässt sich mit verwaltetem Code oder als PowerShell-Cmdlets verwenden, um Anpassungen an Websites zu automatisieren. Installiert wird sie als Nuget-Paket (verwalteter Code), aus der PowerShell Gallery oder mit einer Installationsdatei (ebenfalls PowerShell). Neue Releases folgen in der Regel monatlich.

Die Engine ist kompatibel zu SharePoint Online und On-Premises (2013 und 2016), wobei der Fokus bei der Entwicklung durch die Community eher auf SharePoint Online liegt. Sämtliche Aktionen erfolgen über das Client Side Object Model (CSOM) und somit über die SharePoint-API. Dies bietet den entscheidenden Vorteil, dass der Code nicht auf dem SharePoint-Server, sondern auf einem normalen Client ausgeführt werden kann.

SharePoint_PnP

Provisioning-Template und -Schema

Ein zentraler Bestandteil, neben weiteren praktischen Funktionen und Cmdlets, ist die Möglichkeit Anpassungen und Assets aus Seiten in ein XML-Template zu exportieren und in (andere) Seiten zu importieren. Die Möglichkeiten dieser XML-Datei sind jeweils im aktuellen Provisioning-Schema von PnP beschrieben.

Folgendes kurze Beispiel zeigt dieses Vorgehen mit Hilfe der beiden PowerShell-Cmdlets Get-PnPProvisioningTemplate und Apply-PnPProvisioningTemplate auf.

Exportieren des XML-Templates aus einer bestehenden Website mittels PowerShell:

Connect-PnPOnline -Url https://contoso.sharepoint.com/sites/marketing
Get-PnPProvisioningTemplate -Out template.xml

Daraus resultiert folgendes Template (nur der Ausschnitt einer benutzerdefinierten Liste wird gezeigt):

<?xml version="1.0"?>
<pnp:Provisioning xmlns:pnp="http://schemas.dev.office.com/PnP/2016/05/ProvisioningSchema">
  <pnp:Preferences Generator="OfficeDevPnP.Core, Version=2.15.1705.0, Culture=neutral, PublicKeyToken=3751622786b357c2" />
  <pnp:Templates ID="CONTAINER-TEMPLATE-EE20A9E57E2C4B4185C4D497F9E6274D">
    <pnp:ProvisioningTemplate ID="TEMPLATE-EE20A9E57E2C4B4185C4D497F9E6274D" Version="1" BaseSiteTemplate="STS#0">
		<!-- ... -->
		<pnp:Lists>
		<!-- ... -->
			<pnp:ListInstance Title="Meine Liste" Description="" DocumentTemplate="" TemplateType="100" Url="Lists/Meine Liste" MinorVersionLimit="0" MaxVersionLimit="0" DraftVersionVisibility="0" TemplateFeatureID="00bfea71-de22-43b2-a848-c05709900100" EnableFolderCreation="false">
			  <pnp:ContentTypeBindings>
				<pnp:ContentTypeBinding ContentTypeID="0x01" Default="true" />
				<pnp:ContentTypeBinding ContentTypeID="0x0120" />
			  </pnp:ContentTypeBindings>
			  <pnp:Views>
				<View Name="{A4F02C0C-9C2D-4243-B4B9-9EF42BCD7A3A}" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" Type="HTML" DisplayName="All Items" Url="/sites/debug/Lists/Meine Liste/AllItems.aspx" Level="1" BaseViewID="1" ContentTypeID="0x" ImageUrl="/_layouts/15/images/generic.png?rev=40">
				  <Query>
					<OrderBy>
					  <FieldRef Name="ID" />
					</OrderBy>
				  </Query>
				  <ViewFields>
					<FieldRef Name="LinkTitle" />
				  </ViewFields>
				  <RowLimit Paged="TRUE">30</RowLimit>
				  <JSLink>clienttemplates.js</JSLink>
				</View>
			  </pnp:Views>
			</pnp:ListInstance>
			<!-- ... -->
		</pnp:Lists>
		<!-- ... -->
    </pnp:ProvisioningTemplate>
  </pnp:Templates>
</pnp:Provisioning>

Importieren des Template in eine andere bestehende Website mittels PowerShell (die benutzerdefinierte Liste wird dabei erstellt):

Connect-PnPOnline -Url https://contoso.sharepoint.com/sites/sales
Apply-PnPProvisioningTemplate -Path template.xml

Hier gilt es anzumerken, dass das Provisioning-Schema derzeit noch nicht den gesamten Funktionsumfang von SharePoint abdeckt. So werden z.B. Inhalte von Seiten und Listen oder Einstellungen von Webparts nicht immer komplett exportiert. Fehlende Inhalte und Einstellungen können entweder im generierten XML-Template manuell ergänzt oder nachträglich per Script direkt in der Site angepasst werden.

Zudem ist es wichtig, dass das XML-Template dem Schema entspricht, also valid ist. Dies wird erschwert, da teilweise z.B. sogar die missachtete Gross-/Kleinschreibung von Attribut-Werten zu einem invaliden Template führen kann.

Tipp an dieser Stelle: Lade dir das aktuelle PnP-Provisioning-Schema herunter, schnapp dir ein XML-Validierungstool deiner Wahl (z.B. Notepad++ mit dem Plugin „XML Tools“) und validiere dein Provisioning-Template. Du sparst dir viel Zeit und Ärger beim Anwenden, falls sich ein Fehler eingeschlichen hat.

Templates dynamisch anwenden

Weiter können wir uns von PnP zu Nutze machen, dass sich Templates mit Hilfe des XMLSharePointTemplateProvider sehr einfach direkt aus einer SharePoint-Dokumentenbibliothek laden lassen. So können z.B. verschiedene Ausprägungen einer Site als XML-Template formuliert und in einer zentralen Dokumentenbibliothek abgelegt werden. Hier können diese auch jederzeit angepasst werden (inkl. Versionsverwaltung). Werden nun spezielle Assets zu einem bestimmten Zeitpunkt auf einer Site benötigt, können diese dynamisch durch Anwenden eines der Templates zur Site hinzugefügt werden.

Folgendes Beispiel zeigt auf, wie mit dieser Methode die obenstehende Beispiel-Liste dynamisch zu einer Site hinzugefügt werden kann. Im Template werden dazu noch Parameter eingefügt:

  • {parameter:ListTitle}: Titel der dynamisch erzeugten Liste
  • {parameter:ListUrl}: URL der Liste (auch in URL der View verwendet)
  • {guid}: Automatisch neuerstellte GUID für den Namen der View

Template für die Liste mit eingefügten Parametern:

<?xml version="1.0"?>
<pnp:Provisioning xmlns:pnp="http://schemas.dev.office.com/PnP/2016/05/ProvisioningSchema">
  <pnp:Preferences Generator="OfficeDevPnP.Core, Version=2.15.1705.0, Culture=neutral, PublicKeyToken=3751622786b357c2" />
  <pnp:Templates ID="CONTAINER-TEMPLATE-EE20A9E57E2C4B4185C4D497F9E6274D">
    <pnp:ProvisioningTemplate ID="TEMPLATE-EE20A9E57E2C4B4185C4D497F9E6274D" Version="1" BaseSiteTemplate="STS#0">
		<!-- ... -->
		<pnp:Lists>
		<!-- ... -->
			<pnp:ListInstance Title="{parameter:ListTitle}" Description="" DocumentTemplate="" TemplateType="100" Url="{parameter:ListUrl}" MinorVersionLimit="0" MaxVersionLimit="0" DraftVersionVisibility="0" TemplateFeatureID="00bfea71-de22-43b2-a848-c05709900100" EnableFolderCreation="false">
			  <pnp:ContentTypeBindings>
				<pnp:ContentTypeBinding ContentTypeID="0x01" Default="true" />
				<pnp:ContentTypeBinding ContentTypeID="0x0120" />
			  </pnp:ContentTypeBindings>
			  <pnp:Views>
				<View Name="{guid}" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" Type="HTML" DisplayName="All Items" Url="{parameter:ListUrl}/AllItems.aspx" Level="1" BaseViewID="1" ContentTypeID="0x" ImageUrl="/_layouts/15/images/generic.png?rev=40">
				  <Query>
					<OrderBy>
					  <FieldRef Name="ID" />
					</OrderBy>
				  </Query>
				  <ViewFields>
					<FieldRef Name="LinkTitle" />
				  </ViewFields>
				  <RowLimit Paged="TRUE">30</RowLimit>
				  <JSLink>clienttemplates.js</JSLink>
				</View>
			  </pnp:Views>
			</pnp:ListInstance>
			<!-- ... -->
		</pnp:Lists>
		<!-- ... -->
    </pnp:ProvisioningTemplate>
  </pnp:Templates>
</pnp:Provisioning>

Zum Anwenden des Template wird dann dieser Code z.B. in einem Webservice ausgeführt:

using (var ctx = new ClientContext("https://contoso.sharepoint.com/sites/dev-team"))
{
    // Verbindung zu Template-Folder in der zentralen Bibliothek herstellen
    var absoluteSiteUrl = "https://contoso.sharepoint.com/sites/templates";
    var templateFolderPath = "ListTemplates/CustomLists"; // URL der Bibliothek & Verzeichnispfad
    var provider = new XMLSharePointTemplateProvider(ctx, absoluteSiteUrl, templateFolderPath);

    // Provisioning Template laden
    ProvisioningTemplate template = provider.GetTemplate("template.xml");

    // Parameter zu Template hinzufügen (Titel und URL)
    template.Parameters.Add("ListTitle", "Meine Liste");
    template.Parameters.Add("ListUrl", "Lists/MyList");

    // Template anwenden -> Liste erstellen
    ctx.Web.ApplyProvisioningTemplate(template);
    ctx.ExecuteQuery();
}

Ein ähnliches Vorgehen ist übrigens auch client-seitig aus JavaScript bzw. TypeScript-Code mit Hilfe der PnP-JS-Core-Bibliothek möglich. Dann allerdings unter Angabe eines JSON- statt eines XML-Templates. Dokumentation der Funktion hier.

Einfachere und schnellere SharePoint-Entwicklung dank PnP

Für uns bedeutet der Einsatz von PnP in der SharePoint-Entwicklung:

  • Höhere Produktivität: Einfache Cmdlets bzw. Methoden aufrufen statt etliche Zeilen Code zu schreiben.
  • Einfaches Provisioning: Ganze Portale können einfach und nachvollziehbar per Skript erstellt werden.
  • Flexibilität: Templates anpassen und neu anwenden. Keine umfangreichen Anpassungen und schon gar nicht Solutions neu installieren.
  • Bereit für die Zukunft: Inhaltstypen, Felder und Listen ganz ohne klassische Feature-Framework-Elemente einzusetzen. Einer zukünftigen Migration steht nichts mehr im Weg. Ebenso kann dieser Ansatz ohne weiteres für SharePoint Online eingesetzt werden.

Auch deshalb ist die SharePoint PnP Remote Provisioning Engine ein zentraler Bestandteil der ADVIS eSuite.

Andreas Hebeisen
Software Engineer

Links

SharePoint Patterns and Practices auf GitHub:
https://github.com/SharePoint/PnP

PnP PowerShell:
https://github.com/OfficeDev/PnP-PowerShell

PnP-JS-Core:
https://github.com/SharePoint/PnP-JS-Core

ADVIS eSuite:
https://www.advis.ch/loesungen/esuite

0 Responses to “Dynamischer Einsatz der PnP Remote Provisioning Engine”



  1. Schreibe einen Kommentar

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s





%d Bloggern gefällt das: