Start-SPMigration
Version 1.3.4
PowerShell-Werkzeug fuer die Migration von SharePoint-On-Premises-Inhalten ueber das serverseitige Objektmodell (SSOM). Unterstuetzt werden SharePoint Server 2016, SharePoint Server 2019 und SharePoint Server Subscription Edition (SE).
Das Skript kann:
- Dokumentbibliotheken exportieren
- Dateien inklusive Metadaten exportieren
- normale SharePoint-Listen und deren Eintraege exportieren
- exportierte Inhalte wieder in ein Ziel-Web importieren
- beim Export automatisch eine JSON-
MappingTablefuer Feld-, Listen- und Bibliotheks-Mappings erzeugen - beim Import dieselbe
MappingTablefuer Container- und Metadaten-Mappings verwenden - grosse Dokumente streambasiert exportieren und importieren, ohne die komplette Datei in den Arbeitsspeicher zu laden
- Fehler einzelner Dateien in
ImportErrors-yyyyMMdd-HHmmss.csvprotokollieren und mit der naechsten Datei fortfahren
Voraussetzungen
- SharePoint Server 2016, SharePoint Server 2019 oder SharePoint Server Subscription Edition
- lokale Ausfuehrung auf einem SharePoint-Farmserver; SSOM kann keine entfernte Farm adressieren
- 64-Bit Windows PowerShell (Desktop Edition), nicht PowerShell 7
- Hauptskript: Windows PowerShell 4.0 oder neuer
- GUI: Windows PowerShell 5.0 oder neuer im STA-Modus; Windows PowerShell 5.1 und Windows Server mit Desktop Experience werden empfohlen
- Farm- und Web-Berechtigungen fuer die ausgefuehrten Export-/Importaktionen
Das Werkzeug versucht zuerst das SharePoint-Modul und anschliessend den auf klassischen Farmen ueblichen Snap-in-Fallback zu laden:
Import-Module SharePointServer
Add-PSSnapin Microsoft.SharePoint.PowerShell
Die lokale Farmversion wird anhand von SPFarm.Local.BuildVersion erkannt. Die Buildbereiche von 2016, 2019 und Subscription Edition werden akzeptiert; andere SharePoint-Versionen werden abgelehnt. Die Umgebung kann vor einer Migration separat geprueft werden:
.\Start-SPMigration.ps1 -ValidateEnvironment
Migration zwischen zwei Farmen
Eine Migration zwischen 2016, 2019 und Subscription Edition erfolgt mit SSOM zwingend zweistufig:
- Export lokal auf einem Server der Quellfarm ausfuehren.
- Den kompletten Exportordner auf einen Server der Zielfarm kopieren.
- Import dort lokal gegen das Ziel-Web ausfuehren.
Vorgesehene Upgrade-Pfade sind insbesondere 2016 nach 2019, 2016 nach SE und 2019 nach SE. Ein kombinierter Export und Import in demselben Prozess ist nur sinnvoll, wenn Quelle und Ziel in derselben lokalen Farm liegen. Downgrades von SE nach 2019/2016 oder von 2019 nach 2016 erzeugen eine Warnung, da neuere Artefakte im Ziel fehlen koennen.
Dateien im Projekt
Start-SPMigration.ps1: Hauptskript fuer Export und optionalen ImportStart-SPMigrationGUI.ps1: grafische Oberflaeche; die aktuelle Programmversion wird im Fenstertitel angezeigtmapping.sample.json: Beispiel fuer die aktuelle MappingTablecolumn-mapping-defaults.sample.json: Beispiel fuer wiederverwendbare Column-Mapping-Defaults
Exportierte Struktur
Beim Export entsteht unter -OutputPath folgende Struktur:
OutputPath
|-- Files
| |-- <Bibliothek>
| | |-- Unterordner
| | | |-- Dokument.pdf
| | | |-- Dokument.pdf.properties.json
|-- Lists
| |-- ListeA.json
|-- MappingTable.json
|-- manifest.csv
Dateien
- Die Originaldatei wird in
Files\<Bibliothek>\...gespeichert. - Die Metadaten liegen direkt daneben als Sidecar-Datei:
Dateiname.ext.properties.json manifest.csventhaelt ausserdem Container-Eintraege fuer Listen und Dokumentbibliotheken
Listen
- Pro Liste wird genau eine JSON-Datei unter
Lists\erzeugt. - Die Eintraege enthalten insbesondere:
ContentTypeId(nur Exportinformation)FieldValuesFieldTextValuesFields
Wichtige Metadaten
Fuer den Import sind vor allem diese Informationen relevant:
FieldValuesFieldTextValues- interne Feldnamen (
InternalName)
ContentTypeId und ContentTypeName der Quelle werden nur als Exportinformation gespeichert und beim Import vollstaendig ignoriert. Der Import behaelt den vom Zielcontainer vorgegebenen Content Type und fuehrt ausschliesslich das Columnmapping von SourceInternalName auf TargetInternalName aus. Dadurch duerfen sich Content Types und Spaltennamen zwischen Quelle und Ziel unterscheiden.
MappingTable.json
Beim Export wird automatisch eine MappingTable.json erzeugt. Diese Datei enthaelt:
LibraryMappings: Mapping von Quellbibliothek auf ZielbibliothekListMappings: Mapping von Quellliste auf ZiellisteMetadataColumnMappings.SystemColumns: erkannte SystemspaltenMetadataColumnMappings.CustomColumns: erkannte eigene Fachspalten
Beispiel:
{
"SchemaVersion": 2,
"ToolVersion": "1.3.4",
"GeneratedAtUtc": "2026-04-15T08:00:00.0000000Z",
"SourceWebUrl": "http://sharepoint/sites/Quelle",
"SourceSharePointProduct": "SharePoint Server 2016",
"SourceSharePointBuild": "16.0.5508.1000",
"LibraryMappings": [
{
"ObjectType": "DocumentLibrary",
"SourceTitle": "Documents",
"TargetTitle": "Dokumente",
"BaseType": "DocumentLibrary",
"BaseTemplate": 101,
"RootFolderUrl": "/Documents",
"Hidden": false
}
],
"ListMappings": [
{
"ObjectType": "List",
"SourceTitle": "TestListe",
"TargetTitle": "ZielTestListe",
"BaseType": "GenericList",
"BaseTemplate": 100,
"RootFolderUrl": "/Lists/TestListe",
"Hidden": false
}
],
"MetadataColumnMappings": {
"SystemColumns": [
{
"ObjectType": "List",
"ContainerSourceTitle": "Kalender",
"SourceInternalName": "EventDate",
"SourceCanonicalInternalName": "EventDate",
"SourceSupportingInternalNames": [],
"TargetInternalName": "EventDate",
"DisplayName": "Beginnt",
"TypeAsString": "DateTime",
"Hidden": false,
"ReadOnly": false,
"Sealed": true,
"IsSystemColumn": true,
"ImportSupported": true
}
],
"CustomColumns": [
{
"ObjectType": "DocumentLibrary",
"ContainerSourceTitle": "Documents",
"SourceInternalName": "SecurityClearance",
"SourceCanonicalInternalName": "SecurityClearance",
"SourceSupportingInternalNames": [
"SecurityClearance_0"
],
"TargetInternalName": "GMNSecurityClearance",
"DisplayName": "Security Clearance",
"TypeAsString": "TaxonomyFieldType",
"Hidden": false,
"ReadOnly": false,
"Sealed": false,
"IsSystemColumn": false,
"ImportSupported": true
}
]
}
}
Fuer das Mapping ist vor allem relevant:
SchemaVersion: aktuell Version 2; Version 1 wird beim Laden auf Version 2 normalisiert, neuere unbekannte Versionen werden abgelehntToolVersion,SourceSharePointProductundSourceSharePointBuild: dokumentieren die erzeugende Tool- und Quellfarm-VersionTargetTitle: Zielname von Liste oder BibliothekTargetInternalName: Zielfeld fuer die exportierte MetadatenspalteSystemColumns: SharePoint-Standardfelder wieEventDate,EndDate,TitleoderCreatedCustomColumns: eigene Fachspalten, die im Ziel oft umbenannt oder anders aufgebaut sindSourceSupportingInternalNames: technische Begleitspalten wie_0werden nur noch informativ aufgefuehrt und nicht separat gemapptImportSupported: steuert, ob eine Spalte beim Import ueberhaupt beruecksichtigt wird- Sind Rohwert und Textwert einer Quellspalte leer, wird das Mapping fuer dieses Element uebersprungen. Das Zielfeld wird dann weder geleert noch anderweitig veraendert.
- Taxonomy-Felder (Einfach- und Mehrfachwerte) werden beim Import ueber den exportierten
TermGuidgesetzt; dabei wird angenommen, dass dieselben Terme im Ziel bereits mit identischer GUID existieren - Taxonomy-Werte werden sowohl als strukturiertes
Label + TermGuidals auch im SharePoint-FormatWssId;#Label|TermGuidgelesen. Neue Exporte normalisieren den Rohwert bereits beim Schreiben des Sidecars. - Die exportierte
WssIdwird bewusst nicht uebernommen: Sie ist nur innerhalb der Quell-SiteCollection gueltig. SharePoint loest beim Setzen des Feldwerts die zielseitigeWssIdauf und legt den Eintrag in derTaxonomyHiddenListbei Bedarf selbst an. Die Hidden List soll deshalb nicht separat migriert oder vorab befuellt werden. - Klassische
Lookup- undLookupMulti-Spalten werden derzeit explizit als nicht importierbar markiert. Quellseitige Lookup-IDs sind in einer anderen Farm nicht portabel; ein korrekter Ausbau benoetigt ein fachliches Schluessel-Mapping und einen zweiphasigen Import.
Wenn eine Ziel-Liste oder Ziel-Bibliothek nicht existiert, gibt das Skript eine Warnung aus, dass dieser Container manuell angelegt werden soll.
Column Mapping Defaults
Wenn Bibliotheks- und Listen-Mappings je Migration unterschiedlich sind, die Spalten-Mappings aber gleich bleiben, kann die GUI eine separate Column-Defaults-Datei verwenden.
- Die
MappingTable.jsonbleibt migrationsspezifisch und enthaelt weiterhinLibraryMappings,ListMappingsund die konkret angewendetenMetadataColumnMappings. - Die Defaults-Datei enthaelt nur wiederverwendbare Spaltenregeln unter
Rules. - In der GUI kann ein Defaults-Pfad im Feld
ColumnDefaultsgepflegt werden. Nach einem Export werden vorhandene Defaults automatisch auf die frisch geladeneMappingTable.jsonangewendet und gespeichert. - Mit
Anwendenkoennen Defaults erneut auf die aktuelle MappingTable gelegt werden. Danach bleiben manuelle Anpassungen pro Migration weiterhin moeglich. - Mit
Speichernerzeugt die GUI aus den aktuellen Column-Mappings ein Defaults-Template. Gleichartige Spalten werden dabei aufContainerSourceTitle = "*"generalisiert; widerspruechliche Regeln bleiben container-spezifisch.
Regeln werden von spezifisch nach allgemein angewendet:
ObjectType + ContainerSourceTitle + SourceInternalNameObjectType + * + SourceInternalName* + ContainerSourceTitle + SourceInternalName* + * + SourceInternalName
Beispiel:
{
"SchemaVersion": 1,
"TemplateType": "ColumnMappings",
"Rules": [
{
"ObjectType": "*",
"ContainerSourceTitle": "*",
"SourceInternalName": "SecurityClearance",
"TargetInternalName": "GMNSecurityClearance",
"ImportSupported": true
}
]
}
Parameter
Web- und Pfadparameter
SourceUrl: Quell-Web; beim Export erforderlichTargetUrl: Ziel-Web; beim Import erforderlich
OutputPath ist optional. Standard ist .\SPMigrationOutput im aktuellen Verzeichnis.
Umgebungspruefung
ValidateEnvironment: prueft Windows PowerShell, x64-Prozess, SharePoint-Cmdlets, Taxonomy-Assembly und die lokale SharePoint-2016/2019/SE-Farm, ohne eine Migration zu starten
Exportparameter
Export: fuehrt den Export ausIncludeHiddenLibraries: exportiert auch versteckte BibliothekenIncludeHiddenLists: exportiert auch versteckte Listen
Importparameter
Import: fuehrt den Import aus einem vorhandenen Exportordner ausMappingTable: JSON-Datei mit Listen-, Bibliotheks- und Spalten-MappingsImportFiles: importiert nur Dateien/BibliothekenImportLists: importiert nur ListenOverwrite: ueberschreibt vorhandene Dateien beim Import
Hinweis:
- Wenn weder
ImportFilesnochImportListsgesetzt sind, werden beim Import beide Bereiche verarbeitet. - Wird
MappingTablenicht angegeben, verwendet das Skript standardmaessigOutputPath\MappingTable.json. - Die alte CSV-Variante wird fuer reines Feldmapping weiterhin als Fallback gelesen.
- Werden keine Schalter gesetzt, leitet das Skript den Modus weiterhin aus
SourceUrlundTargetUrlab. - Wenn
Overwritenicht gesetzt ist und eine Datei bereits existiert, wird bei aktiver Versionierung eine neue Version geschrieben; ohne Versionierung wird die Datei uebersprungen. - Nicht importierbare Systemfelder wie
Attachments,Created,Modified,AuthoroderEditorwerden automatisch aus der MappingTable herausgehalten bzw. beim Import uebersprungen. - Vor dem Speichern prueft das Skript fehlende Pflichtfelder. Wenn ein einzelnes Listen- oder Datei-Metadatenobjekt trotzdem nicht gespeichert werden kann, wird es mit Kontext-Warnung uebersprungen und der Import laeuft weiter.
- Fehler bei einzelnen Dateien stoppen den restlichen Dateiimport nicht. Sie werden im Exportordner in einer Datei
ImportErrors-yyyyMMdd-HHmmss.csvmit Importphase, Datei, Bibliothek, Ziel-Web und Fehlerursache protokolliert. - Beim Listenimport legt das Skript bei Bedarf ein verstecktes Textfeld
StartSPMigrationSourceUniqueIdin der Zielliste an. Wiederholte Imports aktualisieren damit vorhandene Elemente anhand der exportierten Source-UniqueIdstatt sie erneut anzulegen.
Beispiele
SSOM-Umgebung pruefen
.\Start-SPMigration.ps1 -ValidateEnvironment
Nur Export
.\Start-SPMigration.ps1 `
-SourceUrl "http://sharepoint/sites/Quelle" `
-Export `
-IncludeHiddenLists `
-IncludeHiddenLibraries
Nur Import
.\Start-SPMigration.ps1 `
-TargetUrl "http://sharepoint/sites/Ziel" `
-Import `
-MappingTable "C:\Temp\SP-Export\MappingTable.json"
Farm exportieren, MappingTable anpassen und auf 2016, 2019 oder SE importieren
.\Start-SPMigration.ps1 `
-SourceUrl "http://sharepoint/sites/Quelle" `
-OutputPath "C:\Temp\SP-Export" `
-Export
Danach den kompletten Ordner C:\Temp\SP-Export auf den Farmserver des Ziels kopieren und MappingTable.json bearbeiten. Dort insbesondere TargetTitle sowie TargetInternalName pruefen.
Anschliessend:
.\Start-SPMigration.ps1 `
-OutputPath "C:\Temp\SP-Export" `
-TargetUrl "http://sharepoint/sites/Ziel" `
-Import `
-MappingTable "C:\Temp\SP-Export\MappingTable.json"
Nur Dateien importrelevant ausfuehren
.\Start-SPMigration.ps1 `
-TargetUrl "http://sharepoint/sites/Ziel" `
-Import `
-MappingTable "C:\Temp\SP-Export\MappingTable.json" `
-ImportFiles `
-Overwrite
Nur Listen importrelevant ausfuehren
.\Start-SPMigration.ps1 `
-TargetUrl "http://sharepoint/sites/Ziel" `
-Import `
-MappingTable "C:\Temp\SP-Export\MappingTable.json" `
-ImportLists
Aktuelles Verhalten beim Import
Dokumentbibliotheken
- Dateien werden in die per
MappingTable.jsonaufgeloeste Zielbibliothek importiert. - Unterordner werden bei Bedarf angelegt.
- Metadaten werden anschliessend ueber die
MetadataColumnMappingsgesetzt.
Listen
- Listeneintraege werden neu angelegt oder bei erneutem Import ueber
StartSPMigrationSourceUniqueIdwiedergefunden und aktualisiert. - Feldwerte werden ueber
FieldValues,FieldTextValuesundMetadataColumnMappingsgemappt.
GUI-Logging und Mapping-Bearbeitung
- Beim Import protokolliert die GUI fuer jeden verarbeiteten Columnwert, ob die Zuweisung am Item erfolgreich war oder mit welchem Fehler sie uebersprungen wurde. Das Log nennt Container bzw. Item sowie Quell- und Zielspalte, schreibt aber nicht den eigentlichen Feldinhalt mit.
- In den Mapping-Tabs
Bibliotheken,Listen,System ColumnsundCustom Columnskann eine Zeile per Rechtsklick undZeile loeschenvollstaendig entfernt werden. Beim Speichern wird sie entsprechend nicht mehr in dieMappingTable.jsongeschrieben.
Bekannte Einschraenkungen
- Die Zielaufloesung kann ueber
MappingTable.jsonmitTargetTitleueberschrieben werden. - Listenanhaenge werden derzeit noch nicht physisch mit importiert.
- Ordner in normalen Listen werden beim Import derzeit uebersprungen.
Lookup- undLookupMulti-Spalten werden nicht importiert, weil Quell-IDs auf der Zielfarm keine stabile Bedeutung haben.- SharePoint-Gruppen in Personenfeldern werden exportseitig erkannt, aber noch nicht automatisch einer Zielgruppe zugeordnet; ein nicht aufloesbarer nichtleerer Wert wird als Feldfehler gemeldet.
- Fehlende Ziellisten oder Zielbibliotheken werden derzeit nicht automatisch angelegt; das Skript gibt stattdessen eine Warnung zur manuellen Anlage aus.
- Quell-Content-Types werden beim Import nicht gemappt oder gesetzt; der Zielcontainer bestimmt den Content Type.
- Bereits vorhandene Dateien unter
FilesundListswerden vor einem erneuten Export nicht automatisch entfernt. Fuer jeden produktiven Lauf sollte deshalb ein neuer, leererOutputPathverwendet werden. - Schlaegt das Setzen von Metadaten nach dem Datei-Upload fehl, kann die bereits hochgeladene Datei als Teilimport im Ziel verbleiben. Der Fehler wird protokolliert; eine automatische Rollback-/Quarantaene-Logik ist noch nicht vorhanden.
- Dateiversionen, Check-in/Publish/Approve-Zustaende und Listen-Versionen werden noch nicht vollstaendig rekonstruiert.
- Grosse Listen werden derzeit als eine JSON-Datei verarbeitet; fuer sehr grosse Datenmengen fehlt noch ein paginierter Chunk-Export.
- Sehr spezielle Feldtypen koennen je nach Farm-Konfiguration zusaetzliche Anpassungen benoetigen.
- Das Skript ist fuer SharePoint Server 2016, 2019 und Subscription Edition mit SSOM gedacht, nicht fuer SharePoint Online, CSOM oder PnP PowerShell.
- SharePoint Server 2016 und 2019 haben das Ende des erweiterten Microsoft-Supports erreicht. Das Werkzeug unterstuetzt sie technisch weiter, ersetzt aber keine Plattform-Sicherheitsstrategie.
Empfohlene naechste Ausbaustufen
- Manifestgesteuerte Run-Ordner mit SHA-256-Pruefung, damit keine Altdateien oder falschen Sidecars importiert werden.
- Transaktionaler Dokumentstatus mit Metadaten-Save vor finalem Check-in sowie Rollback oder Quarantaene bei Teilfehlern.
- Zweiphasiges Lookup-Mapping ueber konfigurierbare fachliche Schluessel statt ueber lokale Item-IDs.
- Paginierter Listenexport und chunkweiser Import fuer grosse Listen.
- Einheitliches Errorlog und Abschlussreport fuer Export, Dateien, Listen und einzelne Listenelemente.
- Automatisierte Integrationstests auf je einer SharePoint-2016- und SharePoint-2019-Testfarm.
Empfehlung
Zuerst -ValidateEnvironment ausfuehren. Danach immer in einen neuen, leeren Ausgabeordner exportieren und die exportierten *.properties.json, Listen-JSONs und die MappingTable.json pruefen. Anschliessend Zielnamen und Feldmappings vervollstaendigen und den Import zuerst gegen ein Test-Web laufen lassen.