Das Problem

Bei der Übertragung einer SharePoint Site auf einen anderen Server hat man das Problem, dass zum Beispiel Websitespalten immer im Katalog der Websitesammlung gespeichert werden. Wenn man diese mit der Hand anlegt, dann haben sie aber eine andere ID. Spielt man dann ein Website-Template ein, finden die darin angelegten Listen die Websitespalten nicht.

Die Lösung

Mit der PowerShell kann man Websitespalten provisionieren und dabei fix eine ID mitgeben. Somit kann man ein Script vorbereiten und in die Ziel-Websitesammlung einspielen.

Am einfachsten ist es, wenn man die Root-Website der Quelle als Vorlage abspeichert. Am einfachsten ist es natürlich, wenn man diese Vorlage auf der Zielwebsite gleich verwendet. Das ist aber oft nicht möglich, wenn die Websitesammlung bereits existiert und die Lösung in eine bestehende Website eingespielt werden muss.

Wenn Sie nun das heruntergeladene *.wsp-File umbenennen in *.cab und dann zum Beispiel mit Hilfe von 7-zip in einen Zielordner extrahieren, erhalten Sie die gesamte Struktur, die die Vorlage enthält als Verzeichnisbaum. Suchen Sie in diesem Verzeichnisbaum die Datei ElementsFields.xml. Diese enthält die vollständige Schema-Beschreibung aller Felder. Diese können als Quelle für das zu schreibende PowerShell-Script dienen.

Was man nun noch braucht, wenn das Provisioning auf eine Office365-Installation erfolgen soll, ist die SharePoint-Client-Umgebung. Diese kann man hier herunterladen und entpacken. Kostenlos und easy.

Darüber hinaus muss man folgende Einstellungen machen:

  • Man muss nach dem Auspacken des angebotenen zip-Files in den File-Attributen das Häkchen entfernen, dass die Datei gefährlich ist, weil aus dem Internet
  • Man muss die Execution Policy der PowerShell auf unrestricted setzen.
  • Man muss in der machine.config des verwendeten .NET-Frameworks folgende Erweiterung eintragen:

<configuration>
<runtime>
<loadFromRemoteSources enabled=“true“/><
/runtime>
</configuration>

Wenn man in der SharePoint-Client-Umgebung arbeitet, ist es wichtig, dass man immer darauf achten muss, dass alles, auf das man zugreifen muss, zuerst geladen werden muss. Das erfolgt über die beiden PowerShell-Kommandos Load(x) und ExecuteQuery(). Wenn man das vergisst, bekommt man aber ohnehin eine sprechende Fehlermeldung und weiß gleich, was los ist.

Beispiel

Die Idee für diesen Artikel und die Vorgehensweise habe ich diesem Artikel von Russi Joine entnommen. Hier gibt es auch noch weiterführende Ideen dazu.

[System.Reflection.Assembly]::LoadFrom(„C:TempMicrosoft.SharePoint.Client.dll“)
# define target SPO site collection and credentials to connect with
$siteUrl = “https://<target>.sharepoint.com/”
$username = „<userName>“
$password = Read-Host -Prompt „Enter password“ -AsSecureString

# connect and authenticate to SPO
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
$ctx.Credentials = $credentials

# retrieve all site columns (fields)
$web = $ctx.Web
$fields = $web.Fields
$ctx.Load($web)
$ctx.Load($fields)
$ctx.ExecuteQuery()

# define a new site column as XML – use a custom GUID here!
$fieldOption = [Microsoft.SharePoint.Client.AddFieldOptions]::DefaultValue

$fieldAsXML = „<Field Type=’DateTime‘ DisplayName=’Abschlussdatum‘ Required=’FALSE‘
EnforceUniqueValues=’FALSE‘ Indexed=’FALSE‘ Format=’DateOnly‘ Group=’QMS‘ FriendlyDisplayFormat=’Disabled‘
ID='{a1e6e794-1f63-4f28-981e-36d4733b44e6}‘ StaticName=’Abschlussdatum‘
Name=’Abschlussdatum‘ CalType=’0′ Overwrite=’TRUE‘ />“
$fld = $fields.AddFieldAsXml($fieldAsXML, $true, $fieldOption)

$fieldAsXML = „<Field Type=’Text‘ DisplayName=’Auftrags-Nr‘ Required=’FALSE‘ EnforceUniqueValues=’FALSE‘ Indexed=’FALSE‘ MaxLength=’255′ Group=’QMS‘ ID='{29149142-2729-4876-be39-2b8e2b2fa68f}‘ StaticName=’Auftrags-Nr‘ Name=’Auftrags-Nr‘ Overwrite=’TRUE‘ />“
$fld = $fields.AddFieldAsXml($fieldAsXML, $true, $fieldOption)
$ctx.Load($fld)

$fieldAsXML = „<Field Type=’Choice‘ DisplayName=’Auftragsstatus‘ Required=’FALSE‘
EnforceUniqueValues=’FALSE‘ Indexed=’FALSE‘ Format=’Dropdown‘ FillInChoice=’FALSE‘ Group=’QMS‘
ID='{19f37733-99de-4f17-ac37-d75a4a1f7e5a}‘ StaticName= ‚Auftragsstatus‘ Name=“Auftragsstatus‘ Overwrite=’TRUE‘>
<Default>offen/neu</Default>
<CHOICES>
<CHOICE>offen/neu</CHOICE>
<CHOICE>in Bearbeitung</CHOICE>
<CHOICE>pendent</CHOICE>
<CHOICE>erledigt</CHOICE>
<CHOICE>geprüft</CHOICE>
<CHOICE>abgeschlossen</CHOICE>
</CHOICES>
</Field>“
$fld = $fields.AddFieldAsXml($fieldAsXML, $true, $fieldOption)
$ctx.Load($fld)

$fieldAsXML = „<Field Type=’DateTime‘ DisplayName=’Zieltermin‘ Required=’FALSE‘
EnforceUniqueValues=’FALSE‘ Indexed=’FALSE‘ Format=’DateOnly‘ Group=’QMS‘ FriendlyDisplayFormat=’Disabled‘
ID='{f04c4e0e-6829-4fa0-99fd-7f764335ee19}‘ StaticName=’Zieltermin‘ Name=’Zieltermin‘ Overwrite=’TRUE‘ />“
$fld = $fields.AddFieldAsXml($fieldAsXML, $true, $fieldOption)
$ctx.Load($fld)

$fieldAsXML = „<Field Type=’User‘ DisplayName=’Zuständig‘ List=’UserInfo‘ Required=’FALSE‘
EnforceUniqueValues=’FALSE‘ ShowField=’ImnName‘ UserSelectionMode=’PeopleOnly‘ UserSelectionScope=’0′ Group=’QMS‘
ID='{68165982-71f1-4404-b741-58e057127bb4}‘ StaticName=’Zuständig‘ Name=’Zuständig‘ Overwrite=’TRUE‘ />“
$fld = $fields.AddFieldAsXml($fieldAsXML, $true, $fieldOption)
$ctx.Load($fld)

$ctx.Load($fields)

$ctx.ExecuteQuery()

Ist doch cool, oder?

LG,
Sabine