Enhance Start-SPMigration GUI for SharePoint SSOM compatibility and update mapping schema

- Added version checks to ensure the script runs in 64-bit Windows PowerShell Desktop Edition.
- Implemented checks for STA thread requirement and SharePoint environment validation.
- Updated application version to 1.2.0 and supported mapping schema version to 2.
- Introduced a new function to retrieve SharePoint product support information based on build version.
- Modified mapping table structure to include ToolVersion and additional metadata fields.
- Updated sample mapping JSON to reflect new schema version and added new fields for metadata column mappings.
This commit is contained in:
Torsten Brendgen
2026-08-26 21:39:39 +02:00
parent e02a38c926
commit 90d17be932
4 changed files with 710 additions and 162 deletions
+158 -16
View File
@@ -1,4 +1,6 @@
#requires -Version 5.0
[CmdletBinding()]
param(
[switch]$NoGui
@@ -6,6 +8,21 @@ param(
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$script:ApplicationVersion = "1.2.0"
$script:SupportedMappingSchemaVersion = 2
$editionProperty = $PSVersionTable.PSObject.Properties["PSEdition"]
if ($null -ne $editionProperty -and [string]$editionProperty.Value -ne "Desktop") {
throw "Start-SPMigration GUI muss fuer SharePoint SSOM mit Windows PowerShell (Desktop Edition), nicht mit PowerShell 7, gestartet werden."
}
if (-not [Environment]::Is64BitProcess) {
throw "Start-SPMigration GUI muss in 64-Bit Windows PowerShell gestartet werden."
}
if ([System.Threading.Thread]::CurrentThread.ApartmentState -ne [System.Threading.ApartmentState]::STA) {
throw "Start-SPMigration GUI benoetigt einen STA-Thread. Bitte mit 'powershell.exe -STA -File .\Start-SPMigrationGUI.ps1' starten."
}
class SettingsManager {
[string]$SettingsPath
@@ -781,7 +798,7 @@ class DialogBuilder : BaseComponent {
}
}
# PowerShell 7 can fail to resolve WinForms via `using assembly`, but runtime loading works reliably.
# WinForms and SharePoint SSOM are loaded at runtime in 64-bit Windows PowerShell.
[void](Add-Type -AssemblyName System.Windows.Forms)
[void](Add-Type -AssemblyName System.Drawing)
[System.Windows.Forms.Application]::EnableVisualStyles()
@@ -794,10 +811,14 @@ $script:MigrationScriptPath = Join-Path -Path (Split-Path -Parent $PSCommandPath
$script:IsUpdatingContainerChecks = $false
$script:LastSuggestedMappingPath = ""
$script:CurrentMappingMeta = [ordered]@{
SchemaVersion = 1
SchemaVersion = $script:SupportedMappingSchemaVersion
ToolVersion = $script:ApplicationVersion
GeneratedAtUtc = ""
SourceWebUrl = ""
SourceSharePointProduct = ""
SourceSharePointBuild = ""
}
$script:SharePointEnvironment = $null
$script:IsMigrationRunning = $false
$script:MigrationProcess = $null
$script:MigrationOutputPath = ""
@@ -844,9 +865,95 @@ function Get-ObjectPropertyValue {
return $property.Value
}
function Get-SharePointProductSupportInfo {
param(
[Parameter(Mandatory = $true)]
[version]$BuildVersion
)
$productName = "Nicht unterstuetzte SharePoint-Version"
$isSupported = $false
if ($BuildVersion.Major -eq 16 -and $BuildVersion.Build -ge 4351 -and $BuildVersion.Build -lt 10337) {
$productName = "SharePoint Server 2016"
$isSupported = $true
}
elseif ($BuildVersion.Major -eq 16 -and $BuildVersion.Build -ge 10337 -and $BuildVersion.Build -lt 14326) {
$productName = "SharePoint Server 2019"
$isSupported = $true
}
elseif ($BuildVersion.Major -eq 16 -and $BuildVersion.Build -ge 14326) {
$productName = "SharePoint Server Subscription Edition"
}
return [PSCustomObject]@{
ProductName = $productName
IsSupported = $isSupported
}
}
function Initialize-SharePointPowerShellForGui {
if ($null -eq (Get-Module -Name SharePointServer)) {
Import-Module SharePointServer -ErrorAction Stop
$editionProperty = $PSVersionTable.PSObject.Properties["PSEdition"]
if ($null -ne $editionProperty -and [string]$editionProperty.Value -ne "Desktop") {
throw "Die GUI und SharePoint SSOM werden nur unter 64-Bit Windows PowerShell (Desktop Edition), nicht unter PowerShell 7, unterstuetzt."
}
if (-not [Environment]::Is64BitProcess) {
throw "Die GUI muss fuer SharePoint SSOM in einem 64-Bit-Windows-PowerShell-Prozess ausgefuehrt werden."
}
if ($PSVersionTable.PSVersion -lt [version]"5.0") {
throw ("Die GUI erfordert Windows PowerShell 5.0 oder neuer. Gefunden: {0}" -f $PSVersionTable.PSVersion)
}
if ($null -eq (Get-Command -Name Get-SPWeb -ErrorAction SilentlyContinue)) {
$loadErrors = @()
try {
Import-Module SharePointServer -ErrorAction Stop
}
catch {
$loadErrors += ("Import-Module SharePointServer: {0}" -f $_.Exception.Message)
}
if ($null -eq (Get-Command -Name Get-SPWeb -ErrorAction SilentlyContinue)) {
try {
$registeredSnapIn = Get-PSSnapin -Registered -Name Microsoft.SharePoint.PowerShell -ErrorAction Stop
if ($null -ne $registeredSnapIn -and $null -eq (Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue)) {
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction Stop
}
}
catch {
$loadErrors += ("Add-PSSnapin Microsoft.SharePoint.PowerShell: {0}" -f $_.Exception.Message)
}
}
if ($null -eq (Get-Command -Name Get-SPWeb -ErrorAction SilentlyContinue)) {
throw ("Die SharePoint Server PowerShell-Cmdlets konnten nicht geladen werden. Die GUI muss lokal auf einem SharePoint-Server ausgefuehrt werden. {0}" -f ($loadErrors -join " | "))
}
}
try {
$Host.Runspace.ThreadOptions = "ReuseThread"
}
catch {
}
$farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
if ($null -eq $farm) {
throw "Keine lokale SharePoint-Farm gefunden. SSOM kann nur lokal auf einem SharePoint-Farmserver verwendet werden."
}
$buildVersion = [version]$farm.BuildVersion
$supportInfo = Get-SharePointProductSupportInfo -BuildVersion $buildVersion
if (-not $supportInfo.IsSupported) {
throw ("Nicht unterstuetzte lokale SharePoint-Farm: {0}, Build {1}. Unterstuetzt werden SharePoint Server 2016 und 2019." -f $supportInfo.ProductName, $buildVersion)
}
return [PSCustomObject]@{
ProductName = $supportInfo.ProductName
BuildVersion = $buildVersion.ToString()
PowerShellVersion = $PSVersionTable.PSVersion.ToString()
}
}
@@ -1089,12 +1196,7 @@ function Get-MigrationHostPath {
}
}
$currentProcessPath = (Get-Process -Id $PID).Path
if (-not [string]::IsNullOrWhiteSpace($currentProcessPath) -and [System.IO.File]::Exists($currentProcessPath)) {
return $currentProcessPath
}
throw "Kein PowerShell-Host fuer die Migration gefunden."
throw "Keine 64-Bit-Windows-PowerShell fuer die SSOM-Migration gefunden."
}
function Get-SingleQuotedPowerShellLiteral {
@@ -1414,7 +1516,7 @@ function Get-SourceContainers {
[switch]$IncludeHiddenLists
)
Initialize-SharePointPowerShellForGui
$script:SharePointEnvironment = Initialize-SharePointPowerShellForGui
$web = $null
@@ -1996,9 +2098,12 @@ function New-EmptyMappingTable {
}
return [PSCustomObject]@{
SchemaVersion = 1
SchemaVersion = $script:SupportedMappingSchemaVersion
ToolVersion = $script:ApplicationVersion
GeneratedAtUtc = [System.DateTime]::UtcNow.ToString("o")
SourceWebUrl = $sourceWebUrl
SourceSharePointProduct = ""
SourceSharePointBuild = ""
LibraryMappings = @()
ListMappings = @()
MetadataColumnMappings = [PSCustomObject]@{
@@ -2013,10 +2118,33 @@ function Set-MappingMetaFromObject {
$MappingTable
)
$schemaVersionValue = Get-ObjectPropertyValue -Object $MappingTable -PropertyName "SchemaVersion" -DefaultValue 1
try {
$schemaVersion = [int]$schemaVersionValue
}
catch {
throw ("Ungueltige SchemaVersion in der MappingTable: '{0}'." -f $schemaVersionValue)
}
if ($schemaVersion -lt 1) {
throw ("Ungueltige SchemaVersion in der MappingTable: {0}." -f $schemaVersion)
}
if ($schemaVersion -gt $script:SupportedMappingSchemaVersion) {
throw ("MappingTable-SchemaVersion {0} ist neuer als die von GUI v{1} unterstuetzte Version {2}." -f $schemaVersion, $script:ApplicationVersion, $script:SupportedMappingSchemaVersion)
}
if ($schemaVersion -lt $script:SupportedMappingSchemaVersion) {
Write-UILog -Message ("MappingTable-SchemaVersion {0} wird beim Speichern auf Version {1} aktualisiert." -f $schemaVersion, $script:SupportedMappingSchemaVersion) -Level "WARN"
}
$script:CurrentMappingMeta = [ordered]@{
SchemaVersion = [int](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "SchemaVersion" -DefaultValue 1)
SchemaVersion = $script:SupportedMappingSchemaVersion
ToolVersion = [string](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "ToolVersion" -DefaultValue $script:ApplicationVersion)
GeneratedAtUtc = [string](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "GeneratedAtUtc" -DefaultValue "")
SourceWebUrl = [string](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "SourceWebUrl" -DefaultValue "")
SourceSharePointProduct = [string](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "SourceSharePointProduct" -DefaultValue "")
SourceSharePointBuild = [string](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "SourceSharePointBuild" -DefaultValue "")
}
}
@@ -2057,9 +2185,12 @@ function Get-MappingTableFromUi {
}
return [PSCustomObject]@{
SchemaVersion = [int]$script:CurrentMappingMeta.SchemaVersion
SchemaVersion = $script:SupportedMappingSchemaVersion
ToolVersion = [string]$script:CurrentMappingMeta.ToolVersion
GeneratedAtUtc = if ([string]::IsNullOrWhiteSpace($script:CurrentMappingMeta.GeneratedAtUtc)) { [System.DateTime]::UtcNow.ToString("o") } else { $script:CurrentMappingMeta.GeneratedAtUtc }
SourceWebUrl = $sourceWebUrl
SourceSharePointProduct = [string]$script:CurrentMappingMeta.SourceSharePointProduct
SourceSharePointBuild = [string]$script:CurrentMappingMeta.SourceSharePointBuild
LibraryMappings = @(Convert-DataTableToObjects -Table $script:LibraryMappingsTable -Schema $script:GridSchemas.LibraryMappings)
ListMappings = @(Convert-DataTableToObjects -Table $script:ListMappingsTable -Schema $script:GridSchemas.ListMappings)
MetadataColumnMappings = [PSCustomObject]@{
@@ -2599,7 +2730,7 @@ function Invoke-ImportFromGui {
}
}
$formBuilder = [FormBuilder]::new("Start-SPMigration GUI")
$formBuilder = [FormBuilder]::new(("Start-SPMigration GUI v{0}" -f $script:ApplicationVersion))
$null = $formBuilder.SetSize([int]$script:SettingsManager.Get("WindowWidth", 1400), [int]$script:SettingsManager.Get("WindowHeight", 940)).SetMinimumSize(1200, 820).SetStartPosition("CenterScreen")
$script:MainForm = $formBuilder.Build()
$script:MainForm.KeyPreview = $true
@@ -3033,7 +3164,18 @@ $script:txtOutputPath.Add_TextChanged({
})
$script:MainForm.Add_Shown({
Write-UILog -Message "Start-SPMigration GUI gestartet."
Write-UILog -Message ("Start-SPMigration GUI v{0} gestartet." -f $script:ApplicationVersion)
try {
$script:SharePointEnvironment = Initialize-SharePointPowerShellForGui
Write-UILog -Message ("SSOM-Umgebung erkannt: {0}, FarmBuild={1}, WindowsPowerShell={2}" -f $script:SharePointEnvironment.ProductName, $script:SharePointEnvironment.BuildVersion, $script:SharePointEnvironment.PowerShellVersion)
}
catch {
Write-UILog -Message ("SSOM-Umgebungspruefung fehlgeschlagen: {0}" -f $_.Exception.Message) -Level "ERROR"
$btnLoadContainers.Enabled = $false
$btnRunExport.Enabled = $false
$btnRunImport.Enabled = $false
Show-UiMessage -Message ("Die Migration wurde deaktiviert, weil keine unterstuetzte lokale SharePoint-2016/2019-SSOM-Umgebung erkannt wurde. Fehler: {0}" -f $_.Exception.Message) -Caption "SSOM-Umgebung nicht verfuegbar" -Icon ([System.Windows.Forms.MessageBoxIcon]::Error)
}
Load-UiSettings
Set-MappingTableToUi -MappingTable (New-EmptyMappingTable)
Load-ExistingMappingTableIfAvailable