using assembly System.Windows.Forms using assembly System.Drawing using namespace System.Windows.Forms using namespace System.Drawing [CmdletBinding()] param( [switch]$NoGui ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" class SettingsManager { [string]$SettingsPath [hashtable]$Settings = @{} SettingsManager([string]$AppName) { $appRoot = [Environment]::GetFolderPath("ApplicationData") $appFolder = Join-Path -Path $appRoot -ChildPath $AppName if (-not (Test-Path -LiteralPath $appFolder)) { New-Item -Path $appFolder -ItemType Directory -Force | Out-Null } $this.SettingsPath = Join-Path -Path $appFolder -ChildPath "settings.json" $this.Load() $this.EnsureDefaults() } [void] Load() { if (-not (Test-Path -LiteralPath $this.SettingsPath)) { $this.Settings = @{} return } try { $json = Get-Content -LiteralPath $this.SettingsPath -Raw -Encoding UTF8 | ConvertFrom-Json $this.Settings = @{} if ($null -ne $json) { foreach ($property in $json.PSObject.Properties) { $this.Settings[$property.Name] = $this.ConvertToHashtable($property.Value) } } } catch { $this.Settings = @{} } } [void] EnsureDefaults() { $defaults = [ordered]@{ FontSize = 9 WindowWidth = 1400 WindowHeight = 940 LastSourceUrl = "" LastTargetUrl = "" LastOutputPath = (Join-Path -Path (Get-Location).Path -ChildPath "SPMigrationOutput") LastMappingTablePath = "" } foreach ($key in $defaults.Keys) { if (-not $this.Settings.ContainsKey($key)) { $this.Settings[$key] = $defaults[$key] } } $this.Save() } [void] Save() { $directory = Split-Path -Parent $this.SettingsPath if (-not (Test-Path -LiteralPath $directory)) { New-Item -Path $directory -ItemType Directory -Force | Out-Null } $json = $this.Settings | ConvertTo-Json -Depth 10 [System.IO.File]::WriteAllText($this.SettingsPath, $json, [System.Text.Encoding]::UTF8) } [object] Get([string]$Key) { if ($this.Settings.ContainsKey($Key)) { return $this.Settings[$Key] } return $null } [object] Get([string]$Key, [object]$DefaultValue) { if ($this.Settings.ContainsKey($Key)) { return $this.Settings[$Key] } return $DefaultValue } [void] Set([string]$Key, [object]$Value) { $this.Settings[$Key] = $Value $this.Save() } [bool] Contains([string]$Key) { return $this.Settings.ContainsKey($Key) } hidden [object] ConvertToHashtable([object]$Value) { if ($null -eq $Value) { return $null } if ($Value -is [System.Collections.IDictionary]) { $hash = @{} foreach ($key in $Value.Keys) { $hash[[string]$key] = $this.ConvertToHashtable($Value[$key]) } return $hash } if ($Value -is [System.Management.Automation.PSCustomObject]) { $hash = @{} foreach ($property in $Value.PSObject.Properties) { $hash[$property.Name] = $this.ConvertToHashtable($property.Value) } return $hash } if ($Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string])) { $items = @() foreach ($item in $Value) { $items += $this.ConvertToHashtable($item) } return $items } return $Value } } class LogManager { [string]$LogPath [bool]$EnableConsole = $false LogManager([string]$AppName) { $appRoot = [Environment]::GetFolderPath("ApplicationData") $logFolder = Join-Path -Path $appRoot -ChildPath (Join-Path -Path $AppName -ChildPath "Logs") if (-not (Test-Path -LiteralPath $logFolder)) { New-Item -Path $logFolder -ItemType Directory -Force | Out-Null } $timestamp = Get-Date -Format "yyyyMMdd" $this.LogPath = Join-Path -Path $logFolder -ChildPath ("gui_{0}.log" -f $timestamp) } [void] Info([string]$Message) { $this.Write("INFO", $Message) } [void] Warning([string]$Message) { $this.Write("WARN", $Message) } [void] Error([string]$Message) { $this.Write("ERROR", $Message) } hidden [void] Write([string]$Level, [string]$Message) { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $line = "[{0}] [{1}] {2}" -f $timestamp, $Level, $Message Add-Content -LiteralPath $this.LogPath -Value $line -Encoding UTF8 if ($this.EnableConsole) { Write-Host $line } } } class AccessibilityManager { [SettingsManager]$SettingsManager [LogManager]$LogManager AccessibilityManager([SettingsManager]$SettingsManager, [LogManager]$LogManager) { $this.SettingsManager = $SettingsManager $this.LogManager = $LogManager } [void] RegisterForm([object]$Form) { if ($null -eq $Form) { return } $this.ApplyFont($Form) } [void] RegisterFontControl([object]$Control) { if ($null -eq $Control) { return } $this.ApplyFont($Control) } [void] RegisterFontControls([object[]]$Controls) { foreach ($control in $Controls) { $this.RegisterFontControl($control) } } [void] RegisterAllControls([object]$Container) { if ($null -eq $Container) { return } $this.ApplyFont($Container) foreach ($control in $Container.Controls) { $this.RegisterAllControls($control) } } hidden [void] ApplyFont([object]$Control) { try { $fontSize = [single]$this.SettingsManager.Get("FontSize", 9) $fontFamily = $Control.Font.FontFamily $fontStyle = $Control.Font.Style $Control.Font = New-Object System.Drawing.Font($fontFamily, $fontSize, $fontStyle) } catch { } } } class BaseComponent { static [SettingsManager]$SettingsManager static [LogManager]$LogManager static [AccessibilityManager]$AccessibilityManager static [void] InitializeShared([SettingsManager]$SettingsManager, [LogManager]$LogManager) { [BaseComponent]::SettingsManager = $SettingsManager [BaseComponent]::LogManager = $LogManager [BaseComponent]::AccessibilityManager = [AccessibilityManager]::new($SettingsManager, $LogManager) } [object] GetSetting([string]$Key) { return [BaseComponent]::SettingsManager.Get($Key) } [object] GetSetting([string]$Key, [object]$DefaultValue) { return [BaseComponent]::SettingsManager.Get($Key, $DefaultValue) } [void] LogInfo([string]$Message) { if ($null -ne [BaseComponent]::LogManager) { [BaseComponent]::LogManager.Info($Message) } } } class FormBuilder : BaseComponent { [object]$Form FormBuilder([string]$Title) { $this.Form = New-Object System.Windows.Forms.Form $this.Form.Text = $Title $this.Form.StartPosition = "CenterScreen" [BaseComponent]::AccessibilityManager.RegisterForm($this.Form) } [FormBuilder] SetSize([int]$Width, [int]$Height) { $this.Form.Size = New-Object System.Drawing.Size($Width, $Height) return $this } [FormBuilder] SetMinimumSize([int]$Width, [int]$Height) { $this.Form.MinimumSize = New-Object System.Drawing.Size($Width, $Height) return $this } [FormBuilder] SetStartPosition([string]$Position) { $this.Form.StartPosition = $Position return $this } [FormBuilder] SetWindowState([string]$WindowState) { $this.Form.WindowState = $WindowState return $this } [FormBuilder] AddControl([object]$Control) { $this.Form.Controls.Add($Control) return $this } [FormBuilder] AddControls([object[]]$Controls) { foreach ($control in $Controls) { $this.Form.Controls.Add($control) } return $this } [FormBuilder] RegisterAllAccessibleControls() { [BaseComponent]::AccessibilityManager.RegisterAllControls($this.Form) return $this } [FormBuilder] AddShownHandler([scriptblock]$Handler) { $this.Form.Add_Shown($Handler) return $this } [FormBuilder] AddFormClosingHandler([scriptblock]$Handler) { $this.Form.Add_FormClosing($Handler) return $this } [object] Build() { return $this.Form } [void] Show() { [void]$this.Form.ShowDialog() } } class FlowLayoutPanelBuilder { [object]$Control FlowLayoutPanelBuilder() { $this.Control = New-Object System.Windows.Forms.FlowLayoutPanel $this.Control.Dock = "Fill" $this.Control.AutoScroll = $true $this.Control.FlowDirection = "LeftToRight" $this.Control.WrapContents = $false } [FlowLayoutPanelBuilder] SetDock([string]$Dock) { $this.Control.Dock = $Dock return $this } [FlowLayoutPanelBuilder] SetAutoScroll([bool]$AutoScroll) { $this.Control.AutoScroll = $AutoScroll return $this } [FlowLayoutPanelBuilder] SetFlowDirection([string]$Direction) { $this.Control.FlowDirection = $Direction return $this } [FlowLayoutPanelBuilder] SetWrapContents([bool]$WrapContents) { $this.Control.WrapContents = $WrapContents return $this } [FlowLayoutPanelBuilder] SetPadding([int]$All) { $this.Control.Padding = New-Object System.Windows.Forms.Padding($All) return $this } [FlowLayoutPanelBuilder] AddControl([object]$Control) { $this.Control.Controls.Add($Control) return $this } [FlowLayoutPanelBuilder] AddControls([object[]]$Controls) { foreach ($control in $Controls) { $this.Control.Controls.Add($control) } return $this } [object] Build() { return $this.Control } } class ButtonBuilder : BaseComponent { [object]$Button ButtonBuilder([string]$Text) { $this.Button = New-Object System.Windows.Forms.Button $this.Button.Text = $Text $this.Button.Font = New-Object System.Drawing.Font("Segoe UI", [single]$this.GetSetting("FontSize", 9)) $this.Button.Margin = New-Object System.Windows.Forms.Padding(6) $this.Button.AutoSize = $false } [ButtonBuilder] SetSize([int]$Width, [int]$Height) { $this.Button.Size = New-Object System.Drawing.Size($Width, $Height) return $this } [ButtonBuilder] SetWidth([int]$Width) { $this.Button.Width = $Width return $this } [ButtonBuilder] SetHeight([int]$Height) { $this.Button.Height = $Height return $this } [ButtonBuilder] SetDock([string]$Dock) { $this.Button.Dock = $Dock return $this } [ButtonBuilder] SetEnabled([bool]$Enabled) { $this.Button.Enabled = $Enabled return $this } [ButtonBuilder] AddClickHandler([scriptblock]$Handler) { $this.Button.Add_Click($Handler) return $this } [object] Build() { return $this.Button } } class LabelBuilder : BaseComponent { [object]$Label LabelBuilder([string]$Text) { $this.Label = New-Object System.Windows.Forms.Label $this.Label.Text = $Text $this.Label.Font = New-Object System.Drawing.Font("Segoe UI", [single]$this.GetSetting("FontSize", 9)) $this.Label.AutoSize = $true $this.Label.Margin = New-Object System.Windows.Forms.Padding(6, 8, 6, 6) } [LabelBuilder] SetAutoSize([bool]$AutoSize) { $this.Label.AutoSize = $AutoSize return $this } [LabelBuilder] SetWidth([int]$Width) { $this.Label.Width = $Width return $this } [LabelBuilder] SetHeight([int]$Height) { $this.Label.Height = $Height return $this } [LabelBuilder] SetDock([string]$Dock) { $this.Label.Dock = $Dock return $this } [LabelBuilder] SetTextAlign([object]$Alignment) { $this.Label.TextAlign = $Alignment return $this } [LabelBuilder] SetMargin([int]$Left, [int]$Top, [int]$Right, [int]$Bottom) { $this.Label.Margin = New-Object System.Windows.Forms.Padding($Left, $Top, $Right, $Bottom) return $this } [object] Build() { return $this.Label } } class TreeViewBuilder : BaseComponent { [object]$Control TreeViewBuilder() { $this.Control = New-Object System.Windows.Forms.TreeView $this.Control.Dock = "Fill" $this.Control.HideSelection = $false $this.Control.ShowPlusMinus = $true $this.Control.ShowRootLines = $true $this.Control.FullRowSelect = $true $this.Control.Font = New-Object System.Drawing.Font("Segoe UI", [single]$this.GetSetting("FontSize", 9)) } [TreeViewBuilder] SetDock([string]$Dock) { $this.Control.Dock = $Dock return $this } [TreeViewBuilder] SetCheckBoxes([bool]$CheckBoxes) { $this.Control.CheckBoxes = $CheckBoxes return $this } [TreeViewBuilder] AddEventHandler([string]$EventName, [scriptblock]$Handler) { $this.Control."Add_$EventName"($Handler) return $this } [object] Build() { return $this.Control } } class DataGridViewBuilder : BaseComponent { [object]$Control DataGridViewBuilder() { $this.Control = New-Object System.Windows.Forms.DataGridView $this.Control.Dock = "Fill" $this.Control.AutoSizeColumnsMode = "Fill" $this.Control.ColumnHeadersHeight = 32 $this.Control.Font = New-Object System.Drawing.Font("Segoe UI", [single]$this.GetSetting("FontSize", 9)) $this.Control.RowHeadersVisible = $false $this.Control.AllowUserToDeleteRows = $false $this.Control.MultiSelect = $false $this.Control.SelectionMode = "CellSelect" $this.Control.EditMode = "EditOnEnter" } [DataGridViewBuilder] SetAllowAddRows([bool]$Enabled) { $this.Control.AllowUserToAddRows = $Enabled return $this } [DataGridViewBuilder] SetDock([string]$Dock) { $this.Control.Dock = $Dock return $this } [object] Build() { return $this.Control } } class GroupBoxBuilder : BaseComponent { [object]$Control GroupBoxBuilder([string]$Text) { $this.Control = New-Object System.Windows.Forms.GroupBox $this.Control.Text = $Text $this.Control.Font = New-Object System.Drawing.Font("Segoe UI", [single]$this.GetSetting("FontSize", 9)) $this.Control.Dock = "Fill" $this.Control.Padding = New-Object System.Windows.Forms.Padding(10) } [GroupBoxBuilder] SetDock([string]$Dock) { $this.Control.Dock = $Dock return $this } [GroupBoxBuilder] SetPadding([int]$All) { $this.Control.Padding = New-Object System.Windows.Forms.Padding($All) return $this } [GroupBoxBuilder] AddControl([object]$Control) { $this.Control.Controls.Add($Control) return $this } [GroupBoxBuilder] AddControls([object[]]$Controls) { foreach ($control in $Controls) { $this.Control.Controls.Add($control) } return $this } [object] Build() { return $this.Control } } class PanelBuilder : BaseComponent { [object]$Control PanelBuilder() { $this.Control = New-Object System.Windows.Forms.Panel } [PanelBuilder] SetDock([string]$Dock) { $this.Control.Dock = $Dock return $this } [PanelBuilder] SetPadding([int]$All) { $this.Control.Padding = New-Object System.Windows.Forms.Padding($All) return $this } [PanelBuilder] SetAutoScroll([bool]$AutoScroll) { $this.Control.AutoScroll = $AutoScroll return $this } [PanelBuilder] AddControl([object]$Control) { $this.Control.Controls.Add($Control) return $this } [PanelBuilder] AddControls([object[]]$Controls) { foreach ($control in $Controls) { $this.Control.Controls.Add($control) } return $this } [object] Build() { return $this.Control } } class TabControlBuilder : BaseComponent { [object]$Control TabControlBuilder() { $this.Control = New-Object System.Windows.Forms.TabControl } [TabControlBuilder] SetDock([string]$Dock) { $this.Control.Dock = $Dock return $this } [TabControlBuilder] AddTabPage([object]$TabPage) { $this.Control.TabPages.Add($TabPage) | Out-Null return $this } [object] Build() { return $this.Control } } class TabPageBuilder : BaseComponent { [object]$Control TabPageBuilder([string]$Text) { $this.Control = New-Object System.Windows.Forms.TabPage $this.Control.Text = $Text $this.Control.Padding = New-Object System.Windows.Forms.Padding(10) } [TabPageBuilder] AddControl([object]$Control) { $this.Control.Controls.Add($Control) return $this } [TabPageBuilder] SetPadding([int]$All) { $this.Control.Padding = New-Object System.Windows.Forms.Padding($All) return $this } [object] Build() { return $this.Control } } class DialogBuilder : BaseComponent { [object]$Dialog [string]$DialogType hidden DialogBuilder([string]$Type) { $this.DialogType = $Type switch ($Type) { "Open" { $this.Dialog = New-Object System.Windows.Forms.OpenFileDialog $this.Dialog.Filter = "Alle Dateien (*.*)|*.*" $this.Dialog.RestoreDirectory = $true } "Save" { $this.Dialog = New-Object System.Windows.Forms.SaveFileDialog $this.Dialog.Filter = "Alle Dateien (*.*)|*.*" $this.Dialog.RestoreDirectory = $true $this.Dialog.OverwritePrompt = $true } "Folder" { $this.Dialog = New-Object System.Windows.Forms.FolderBrowserDialog $this.Dialog.ShowNewFolderButton = $true } } } static [DialogBuilder] OpenFile() { return [DialogBuilder]::new("Open") } static [DialogBuilder] SaveFile() { return [DialogBuilder]::new("Save") } static [DialogBuilder] SelectFolder() { return [DialogBuilder]::new("Folder") } [DialogBuilder] SetTitle([string]$Title) { if ($this.DialogType -eq "Folder") { $this.Dialog.Description = $Title } else { $this.Dialog.Title = $Title } return $this } [DialogBuilder] SetFilter([string]$Filter) { if ($this.DialogType -ne "Folder") { $this.Dialog.Filter = $Filter } return $this } [DialogBuilder] SetInitialDirectory([string]$Path) { if ([string]::IsNullOrWhiteSpace($Path)) { return $this } if ($this.DialogType -eq "Folder") { if (Test-Path -LiteralPath $Path) { $this.Dialog.SelectedPath = $Path } } elseif (Test-Path -LiteralPath $Path) { $this.Dialog.InitialDirectory = $Path } return $this } [DialogBuilder] SetSelectedPath([string]$Path) { if ([string]::IsNullOrWhiteSpace($Path)) { return $this } if ($this.DialogType -eq "Folder" -and (Test-Path -LiteralPath $Path)) { $this.Dialog.SelectedPath = $Path } return $this } [DialogBuilder] SetFileName([string]$FileName) { if ($this.DialogType -ne "Folder") { $this.Dialog.FileName = $FileName } return $this } [DialogBuilder] SetCheckFileExists([bool]$CheckFileExists) { if ($this.DialogType -eq "Open") { $this.Dialog.CheckFileExists = $CheckFileExists } return $this } [DialogBuilder] SetOverwritePrompt([bool]$OverwritePrompt) { if ($this.DialogType -eq "Save") { $this.Dialog.OverwritePrompt = $OverwritePrompt } return $this } [object] ShowDialog() { return $this.Dialog.ShowDialog() } [string] GetPath() { if ($this.DialogType -eq "Folder") { return [string]$this.Dialog.SelectedPath } return [string]$this.Dialog.FileName } } [void](Add-Type -AssemblyName System.Windows.Forms) [void](Add-Type -AssemblyName System.Drawing) [System.Windows.Forms.Application]::EnableVisualStyles() $script:SettingsManager = [SettingsManager]::new("SPMigrationTool") $script:LogManager = [LogManager]::new("SPMigrationTool") [BaseComponent]::InitializeShared($script:SettingsManager, $script:LogManager) $script:MigrationScriptPath = Join-Path -Path (Split-Path -Parent $PSCommandPath) -ChildPath "Start-SPMigration.ps1" $script:IsUpdatingContainerChecks = $false $script:LastSuggestedMappingPath = "" $script:CurrentMappingMeta = [ordered]@{ SchemaVersion = 1 GeneratedAtUtc = "" SourceWebUrl = "" } function Get-ObjectPropertyValue { param( $Object, [Parameter(Mandatory = $true)] [string]$PropertyName, $DefaultValue = $null ) if ($null -eq $Object) { return $DefaultValue } if ($Object -is [System.Collections.IDictionary]) { if ($Object.Contains($PropertyName)) { return $Object[$PropertyName] } return $DefaultValue } $property = $Object.PSObject.Properties[$PropertyName] if ($null -eq $property) { return $DefaultValue } if ($null -eq $property.Value) { return $DefaultValue } return $property.Value } function Initialize-SharePointPowerShellForGui { if ($null -eq (Get-Module -Name SharePointServer)) { Import-Module SharePointServer -ErrorAction Stop } } function Test-IsCatalogList { param( [Parameter(Mandatory = $true)] [Microsoft.SharePoint.SPList]$List ) try { return [bool]$List.IsCatalog } catch { return $false } } function Write-UILog { param( [Parameter(Mandatory = $true)] [string]$Message, [ValidateSet("INFO", "WARN", "ERROR")] [string]$Level = "INFO" ) $timestamp = Get-Date -Format "HH:mm:ss" $line = "[{0}] [{1}] {2}" -f $timestamp, $Level, $Message if ($null -ne $script:txtLog) { if ($script:txtLog.TextLength -gt 0) { $script:txtLog.AppendText([Environment]::NewLine) } $script:txtLog.AppendText($line) $script:txtLog.SelectionStart = $script:txtLog.TextLength $script:txtLog.ScrollToCaret() [System.Windows.Forms.Application]::DoEvents() } switch ($Level) { "WARN" { [BaseComponent]::LogManager.Warning($Message) } "ERROR" { [BaseComponent]::LogManager.Error($Message) } default { [BaseComponent]::LogManager.Info($Message) } } } function Show-UiMessage { param( [Parameter(Mandatory = $true)] [string]$Message, [string]$Caption = "Start-SPMigration GUI", [System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::Information ) [void][System.Windows.Forms.MessageBox]::Show($script:MainForm, $Message, $Caption, [System.Windows.Forms.MessageBoxButtons]::OK, $Icon) } function Get-FullPathSafe { param( [string]$Path ) if ([string]::IsNullOrWhiteSpace($Path)) { return "" } try { return [System.IO.Path]::GetFullPath($Path) } catch { return $Path } } function Get-ParentDirectorySafe { param( [string]$Path ) if ([string]::IsNullOrWhiteSpace($Path)) { return "" } if (Test-Path -LiteralPath $Path -PathType Container) { return (Get-FullPathSafe -Path $Path) } $parent = Split-Path -Parent $Path if ([string]::IsNullOrWhiteSpace($parent)) { return "" } return (Get-FullPathSafe -Path $parent) } function Ensure-ParentDirectory { param( [Parameter(Mandatory = $true)] [string]$Path ) $directory = Split-Path -Parent $Path if (-not [string]::IsNullOrWhiteSpace($directory) -and -not (Test-Path -LiteralPath $directory)) { New-Item -Path $directory -ItemType Directory -Force | Out-Null } } function Sync-MappingPathWithOutputPath { param( [switch]$Force ) $outputPath = Get-FullPathSafe -Path $script:txtOutputPath.Text if ([string]::IsNullOrWhiteSpace($outputPath)) { return } $suggestedMappingPath = Join-Path -Path $outputPath -ChildPath "MappingTable.json" $currentMappingPath = [string]$script:txtMappingPath.Text if ( $Force.IsPresent -or [string]::IsNullOrWhiteSpace($currentMappingPath) -or ($currentMappingPath -eq $script:LastSuggestedMappingPath) ) { $script:txtMappingPath.Text = $suggestedMappingPath } $script:LastSuggestedMappingPath = $suggestedMappingPath } function Convert-RecordToLogText { param( $Record ) if ($null -eq $Record) { return $null } if ($Record -is [System.Management.Automation.WarningRecord]) { return "WARNING: {0}" -f $Record.Message } if ($Record -is [System.Management.Automation.ErrorRecord]) { return [string]$Record } if ($Record -is [System.Management.Automation.VerboseRecord]) { return "VERBOSE: {0}" -f $Record.Message } if ($Record -is [System.Management.Automation.DebugRecord]) { return "DEBUG: {0}" -f $Record.Message } if ($Record -is [System.Management.Automation.InformationRecord]) { return [string]$Record.MessageData } return [string]$Record } function Invoke-MigrationScript { param( [Parameter(Mandatory = $true)] [hashtable]$Parameters, [Parameter(Mandatory = $true)] [string]$ActionLabel ) if (-not (Test-Path -LiteralPath $script:MigrationScriptPath)) { throw ("Start-SPMigration.ps1 nicht gefunden: {0}" -f $script:MigrationScriptPath) } $script:MainForm.UseWaitCursor = $true [System.Windows.Forms.Application]::DoEvents() try { Write-UILog -Message ("Starte {0}..." -f $ActionLabel) & $script:MigrationScriptPath @Parameters *>&1 | ForEach-Object { $text = Convert-RecordToLogText -Record $_ if (-not [string]::IsNullOrWhiteSpace($text)) { Write-UILog -Message $text } } Write-UILog -Message ("{0} abgeschlossen." -f $ActionLabel) } finally { $script:MainForm.UseWaitCursor = $false [System.Windows.Forms.Application]::DoEvents() } } function Get-SourceContainers { param( [Parameter(Mandatory = $true)] [string]$SourceUrl, [switch]$IncludeHiddenLibraries, [switch]$IncludeHiddenLists ) Initialize-SharePointPowerShellForGui $web = $null try { $web = Get-SPWeb -Identity $SourceUrl -ErrorAction Stop $documentLibraries = @( $web.Lists | Where-Object { $_.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary -and ($IncludeHiddenLibraries -or -not $_.Hidden) -and -not (Test-IsCatalogList -List $_) } ) $lists = @( $web.Lists | Where-Object { $_.BaseType -ne [Microsoft.SharePoint.SPBaseType]::DocumentLibrary -and ($IncludeHiddenLists -or -not $_.Hidden) -and -not (Test-IsCatalogList -List $_) } ) $items = @() foreach ($library in @($documentLibraries | Sort-Object -Property Title)) { $items += [PSCustomObject]@{ ObjectType = "DocumentLibrary" Title = [string]$library.Title RootFolderUrl = [string]$library.RootFolder.ServerRelativeUrl Hidden = [bool]$library.Hidden BaseTemplate = [int]$library.BaseTemplate ItemCount = [int]$library.ItemCount } } foreach ($list in @($lists | Sort-Object -Property Title)) { $items += [PSCustomObject]@{ ObjectType = "List" Title = [string]$list.Title RootFolderUrl = [string]$list.RootFolder.ServerRelativeUrl Hidden = [bool]$list.Hidden BaseTemplate = [int]$list.BaseTemplate ItemCount = [int]$list.ItemCount } } return $items } finally { if ($null -ne $web) { $web.Dispose() } } } function Set-TreeChildrenChecked { param( [Parameter(Mandatory = $true)] [System.Windows.Forms.TreeNode]$Node, [Parameter(Mandatory = $true)] [bool]$Checked ) foreach ($childNode in $Node.Nodes) { $childNode.Checked = $Checked if ($childNode.Nodes.Count -gt 0) { Set-TreeChildrenChecked -Node $childNode -Checked $Checked } } } function Update-ParentNodeCheckedState { param( [Parameter(Mandatory = $true)] [System.Windows.Forms.TreeNode]$Node ) $parentNode = $Node.Parent if ($null -eq $parentNode) { return } $allChecked = $true foreach ($childNode in $parentNode.Nodes) { if (-not $childNode.Checked) { $allChecked = $false break } } $parentNode.Checked = $allChecked } function Set-AllContainerNodesChecked { param( [Parameter(Mandatory = $true)] [bool]$Checked ) $script:IsUpdatingContainerChecks = $true try { foreach ($rootNode in $script:tvContainers.Nodes) { $rootNode.Checked = $Checked Set-TreeChildrenChecked -Node $rootNode -Checked $Checked } } finally { $script:IsUpdatingContainerChecks = $false } } function Populate-ContainerTree { param( [Parameter(Mandatory = $true)] [object[]]$Containers ) $script:IsUpdatingContainerChecks = $true try { $script:tvContainers.Nodes.Clear() $libraries = @($Containers | Where-Object { $_.ObjectType -eq "DocumentLibrary" }) $lists = @($Containers | Where-Object { $_.ObjectType -eq "List" }) $libraryRootNode = New-Object System.Windows.Forms.TreeNode ("Bibliotheken ({0})" -f $libraries.Count) $libraryRootNode.Checked = $true foreach ($library in $libraries) { $text = "{0} [{1}] Items: {2}" -f $library.Title, $library.RootFolderUrl, $library.ItemCount $node = New-Object System.Windows.Forms.TreeNode $text $node.Checked = $true $node.Tag = [PSCustomObject]@{ ObjectType = $library.ObjectType Title = $library.Title RootFolderUrl = $library.RootFolderUrl } [void]$libraryRootNode.Nodes.Add($node) } $listRootNode = New-Object System.Windows.Forms.TreeNode ("Listen ({0})" -f $lists.Count) $listRootNode.Checked = $true foreach ($list in $lists) { $text = "{0} [{1}] Items: {2}" -f $list.Title, $list.RootFolderUrl, $list.ItemCount $node = New-Object System.Windows.Forms.TreeNode $text $node.Checked = $true $node.Tag = [PSCustomObject]@{ ObjectType = $list.ObjectType Title = $list.Title RootFolderUrl = $list.RootFolderUrl } [void]$listRootNode.Nodes.Add($node) } [void]$script:tvContainers.Nodes.Add($libraryRootNode) [void]$script:tvContainers.Nodes.Add($listRootNode) $script:tvContainers.ExpandAll() } finally { $script:IsUpdatingContainerChecks = $false } } function Get-SelectedContainerUrls { $urls = @() foreach ($rootNode in $script:tvContainers.Nodes) { foreach ($childNode in $rootNode.Nodes) { if ($childNode.Checked -and $null -ne $childNode.Tag) { $rootFolderUrl = [string](Get-ObjectPropertyValue -Object $childNode.Tag -PropertyName "RootFolderUrl" -DefaultValue "") if (-not [string]::IsNullOrWhiteSpace($rootFolderUrl)) { $urls += $rootFolderUrl.Trim() } } } } return @($urls | Sort-Object -Unique) } function Get-SelectableContainerCount { $count = 0 foreach ($rootNode in $script:tvContainers.Nodes) { $count += $rootNode.Nodes.Count } return $count } function Convert-ToDelimitedString { param( $Value ) if ($null -eq $Value) { return "" } if ($Value -is [string]) { return $Value } $parts = @() foreach ($item in @($Value)) { if (-not [string]::IsNullOrWhiteSpace([string]$item)) { $parts += [string]$item } } return ($parts -join ", ") } function Convert-ToStringArray { param( $Value ) if ($null -eq $Value) { return @() } if ($Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string])) { $items = @() foreach ($item in $Value) { if (-not [string]::IsNullOrWhiteSpace([string]$item)) { $items += [string]$item } } return $items } $text = [string]$Value if ([string]::IsNullOrWhiteSpace($text)) { return @() } return @($text -split "\s*[,;]\s*" | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) } $script:GridSchemas = @{ LibraryMappings = @( @{ Name = "ObjectType"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceTitle"; Type = [string]; ReadOnly = $true; FillWeight = 20 } @{ Name = "TargetTitle"; Type = [string]; ReadOnly = $false; FillWeight = 20 } @{ Name = "BaseType"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "BaseTemplate"; Type = [int]; ReadOnly = $true; FillWeight = 10 } @{ Name = "RootFolderUrl"; Type = [string]; ReadOnly = $true; FillWeight = 20 } @{ Name = "Hidden"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } ) ListMappings = @( @{ Name = "ObjectType"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceTitle"; Type = [string]; ReadOnly = $true; FillWeight = 20 } @{ Name = "TargetTitle"; Type = [string]; ReadOnly = $false; FillWeight = 20 } @{ Name = "BaseType"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "BaseTemplate"; Type = [int]; ReadOnly = $true; FillWeight = 10 } @{ Name = "RootFolderUrl"; Type = [string]; ReadOnly = $true; FillWeight = 20 } @{ Name = "Hidden"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } ) SystemColumns = @( @{ Name = "ObjectType"; Type = [string]; ReadOnly = $true; FillWeight = 8 } @{ Name = "ContainerSourceTitle"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceInternalName"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceCanonicalInternalName"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceSupportingInternalNames"; Type = [string]; ReadOnly = $true; FillWeight = 15 } @{ Name = "TargetInternalName"; Type = [string]; ReadOnly = $false; FillWeight = 14 } @{ Name = "DisplayName"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "TypeAsString"; Type = [string]; ReadOnly = $true; FillWeight = 10 } @{ Name = "Hidden"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "ReadOnly"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "Sealed"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "IsSystemColumn"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "ImportSupported"; Type = [bool]; ReadOnly = $false; FillWeight = 8 } ) CustomColumns = @( @{ Name = "ObjectType"; Type = [string]; ReadOnly = $true; FillWeight = 8 } @{ Name = "ContainerSourceTitle"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceInternalName"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceCanonicalInternalName"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "SourceSupportingInternalNames"; Type = [string]; ReadOnly = $true; FillWeight = 15 } @{ Name = "TargetInternalName"; Type = [string]; ReadOnly = $false; FillWeight = 14 } @{ Name = "DisplayName"; Type = [string]; ReadOnly = $true; FillWeight = 12 } @{ Name = "TypeAsString"; Type = [string]; ReadOnly = $true; FillWeight = 10 } @{ Name = "Hidden"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "ReadOnly"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "Sealed"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "IsSystemColumn"; Type = [bool]; ReadOnly = $true; FillWeight = 6 } @{ Name = "ImportSupported"; Type = [bool]; ReadOnly = $false; FillWeight = 8 } ) } function New-DataTableFromSchema { param( [Parameter(Mandatory = $true)] [object[]]$Schema ) $table = New-Object System.Data.DataTable foreach ($columnDefinition in $Schema) { $column = New-Object System.Data.DataColumn($columnDefinition.Name, $columnDefinition.Type) [void]$table.Columns.Add($column) } Write-Output -NoEnumerate $table } function Convert-ToTableCellValue { param( $Value, [Parameter(Mandatory = $true)] [type]$TargetType, [Parameter(Mandatory = $true)] [string]$ColumnName ) if ($ColumnName -eq "SourceSupportingInternalNames") { return (Convert-ToDelimitedString -Value $Value) } if ($null -eq $Value) { if ($TargetType -eq [bool]) { return $false } if ($TargetType -eq [int]) { return 0 } return "" } if ($TargetType -eq [bool]) { return [bool]$Value } if ($TargetType -eq [int]) { try { return [int]$Value } catch { return 0 } } return [string]$Value } function Set-DataTableRows { param( [Parameter(Mandatory = $true)] [System.Data.DataTable]$Table, [Parameter(Mandatory = $true)] [object[]]$Schema, [object[]]$Rows = @() ) $Table.Rows.Clear() foreach ($item in @($Rows)) { $row = $Table.NewRow() foreach ($columnDefinition in $Schema) { $value = Get-ObjectPropertyValue -Object $item -PropertyName $columnDefinition.Name $row[$columnDefinition.Name] = Convert-ToTableCellValue -Value $value -TargetType $columnDefinition.Type -ColumnName $columnDefinition.Name } [void]$Table.Rows.Add($row) } } function Configure-MappingGrid { param( [Parameter(Mandatory = $true)] [System.Windows.Forms.DataGridView]$Grid, [Parameter(Mandatory = $true)] [System.Data.DataTable]$Table, [Parameter(Mandatory = $true)] [object[]]$Schema ) $Grid.DataSource = $Table foreach ($columnDefinition in $Schema) { if ($Grid.Columns.Contains($columnDefinition.Name)) { $column = $Grid.Columns[$columnDefinition.Name] $column.ReadOnly = [bool]$columnDefinition.ReadOnly $column.FillWeight = [single]$columnDefinition.FillWeight if ($columnDefinition.Type -eq [bool]) { $column.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells } } } } function Convert-DataTableToObjects { param( [Parameter(Mandatory = $true)] [System.Data.DataTable]$Table, [Parameter(Mandatory = $true)] [object[]]$Schema ) $items = @() foreach ($row in $Table.Rows) { $item = [ordered]@{} foreach ($columnDefinition in $Schema) { $value = $row[$columnDefinition.Name] if ($value -eq [System.DBNull]::Value) { $value = $null } if ($columnDefinition.Name -eq "SourceSupportingInternalNames") { $item[$columnDefinition.Name] = @(Convert-ToStringArray -Value $value) continue } if ($columnDefinition.Type -eq [bool]) { $item[$columnDefinition.Name] = [bool]$value continue } if ($columnDefinition.Type -eq [int]) { $item[$columnDefinition.Name] = [int]$value continue } $item[$columnDefinition.Name] = [string]$value } $items += [PSCustomObject]$item } return $items } $script:LibraryMappingsTable = New-DataTableFromSchema -Schema $script:GridSchemas.LibraryMappings $script:ListMappingsTable = New-DataTableFromSchema -Schema $script:GridSchemas.ListMappings $script:SystemColumnsTable = New-DataTableFromSchema -Schema $script:GridSchemas.SystemColumns $script:CustomColumnsTable = New-DataTableFromSchema -Schema $script:GridSchemas.CustomColumns function Initialize-MappingTables { if ($null -eq $script:LibraryMappingsTable) { $script:LibraryMappingsTable = New-DataTableFromSchema -Schema $script:GridSchemas.LibraryMappings } if ($null -eq $script:ListMappingsTable) { $script:ListMappingsTable = New-DataTableFromSchema -Schema $script:GridSchemas.ListMappings } if ($null -eq $script:SystemColumnsTable) { $script:SystemColumnsTable = New-DataTableFromSchema -Schema $script:GridSchemas.SystemColumns } if ($null -eq $script:CustomColumnsTable) { $script:CustomColumnsTable = New-DataTableFromSchema -Schema $script:GridSchemas.CustomColumns } } function New-EmptyMappingTable { $sourceWebUrl = "" if ($null -ne $script:txtSourceUrl) { $sourceWebUrl = [string]$script:txtSourceUrl.Text } return [PSCustomObject]@{ SchemaVersion = 1 GeneratedAtUtc = [System.DateTime]::UtcNow.ToString("o") SourceWebUrl = $sourceWebUrl LibraryMappings = @() ListMappings = @() MetadataColumnMappings = [PSCustomObject]@{ SystemColumns = @() CustomColumns = @() } } } function Set-MappingMetaFromObject { param( $MappingTable ) $script:CurrentMappingMeta = [ordered]@{ SchemaVersion = [int](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "SchemaVersion" -DefaultValue 1) GeneratedAtUtc = [string](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "GeneratedAtUtc" -DefaultValue "") SourceWebUrl = [string](Get-ObjectPropertyValue -Object $MappingTable -PropertyName "SourceWebUrl" -DefaultValue "") } } function Set-MappingTableToUi { param( $MappingTable ) Initialize-MappingTables if ($null -eq $MappingTable) { $MappingTable = New-EmptyMappingTable } Set-MappingMetaFromObject -MappingTable $MappingTable $metadataColumnMappings = Get-ObjectPropertyValue -Object $MappingTable -PropertyName "MetadataColumnMappings" -DefaultValue ([PSCustomObject]@{ SystemColumns = @() CustomColumns = @() }) Set-DataTableRows -Table $script:LibraryMappingsTable -Schema $script:GridSchemas.LibraryMappings -Rows @(Get-ObjectPropertyValue -Object $MappingTable -PropertyName "LibraryMappings" -DefaultValue @()) Set-DataTableRows -Table $script:ListMappingsTable -Schema $script:GridSchemas.ListMappings -Rows @(Get-ObjectPropertyValue -Object $MappingTable -PropertyName "ListMappings" -DefaultValue @()) Set-DataTableRows -Table $script:SystemColumnsTable -Schema $script:GridSchemas.SystemColumns -Rows @(Get-ObjectPropertyValue -Object $metadataColumnMappings -PropertyName "SystemColumns" -DefaultValue @()) Set-DataTableRows -Table $script:CustomColumnsTable -Schema $script:GridSchemas.CustomColumns -Rows @(Get-ObjectPropertyValue -Object $metadataColumnMappings -PropertyName "CustomColumns" -DefaultValue @()) if ([string]::IsNullOrWhiteSpace($script:txtSourceUrl.Text) -and -not [string]::IsNullOrWhiteSpace($script:CurrentMappingMeta.SourceWebUrl)) { $script:txtSourceUrl.Text = $script:CurrentMappingMeta.SourceWebUrl } } function Get-MappingTableFromUi { Initialize-MappingTables $sourceWebUrl = $script:CurrentMappingMeta.SourceWebUrl if ([string]::IsNullOrWhiteSpace($sourceWebUrl)) { $sourceWebUrl = [string]$script:txtSourceUrl.Text } return [PSCustomObject]@{ SchemaVersion = [int]$script:CurrentMappingMeta.SchemaVersion GeneratedAtUtc = if ([string]::IsNullOrWhiteSpace($script:CurrentMappingMeta.GeneratedAtUtc)) { [System.DateTime]::UtcNow.ToString("o") } else { $script:CurrentMappingMeta.GeneratedAtUtc } SourceWebUrl = $sourceWebUrl LibraryMappings = @(Convert-DataTableToObjects -Table $script:LibraryMappingsTable -Schema $script:GridSchemas.LibraryMappings) ListMappings = @(Convert-DataTableToObjects -Table $script:ListMappingsTable -Schema $script:GridSchemas.ListMappings) MetadataColumnMappings = [PSCustomObject]@{ SystemColumns = @(Convert-DataTableToObjects -Table $script:SystemColumnsTable -Schema $script:GridSchemas.SystemColumns) CustomColumns = @(Convert-DataTableToObjects -Table $script:CustomColumnsTable -Schema $script:GridSchemas.CustomColumns) } } } function Load-MappingTableFromPath { param( [Parameter(Mandatory = $true)] [string]$Path ) if ([string]::IsNullOrWhiteSpace($Path)) { throw "Bitte einen gueltigen MappingTable-Pfad angeben." } if (-not (Test-Path -LiteralPath $Path)) { throw ("MappingTable nicht gefunden: {0}" -f $Path) } if ([System.IO.Path]::GetExtension($Path) -ine ".json") { throw "Die GUI kann nur JSON-MappingTables bearbeiten." } $mappingTable = Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json Set-MappingTableToUi -MappingTable $mappingTable $script:txtMappingPath.Text = (Get-FullPathSafe -Path $Path) $candidateOutputPath = Get-ParentDirectorySafe -Path $Path if (-not [string]::IsNullOrWhiteSpace($candidateOutputPath)) { $script:txtOutputPath.Text = $candidateOutputPath } Sync-MappingPathWithOutputPath -Force $script:txtMappingPath.Text = (Get-FullPathSafe -Path $Path) Write-UILog -Message ("MappingTable geladen: {0}" -f $Path) } function Save-MappingTableToPath { param( [Parameter(Mandatory = $true)] [string]$Path ) if ([string]::IsNullOrWhiteSpace($Path)) { throw "Bitte einen Pfad fuer die MappingTable angeben." } $resolvedPath = Get-FullPathSafe -Path $Path Ensure-ParentDirectory -Path $resolvedPath $mappingTable = Get-MappingTableFromUi $json = $mappingTable | ConvertTo-Json -Depth 10 [System.IO.File]::WriteAllText($resolvedPath, $json, [System.Text.Encoding]::UTF8) $script:txtMappingPath.Text = $resolvedPath Write-UILog -Message ("MappingTable gespeichert: {0}" -f $resolvedPath) } function Save-UiSettings { $script:SettingsManager.Set("WindowWidth", $script:MainForm.Width) $script:SettingsManager.Set("WindowHeight", $script:MainForm.Height) $script:SettingsManager.Set("LastSourceUrl", [string]$script:txtSourceUrl.Text) $script:SettingsManager.Set("LastTargetUrl", [string]$script:txtTargetUrl.Text) $script:SettingsManager.Set("LastOutputPath", [string]$script:txtOutputPath.Text) $script:SettingsManager.Set("LastMappingTablePath", [string]$script:txtMappingPath.Text) } function Load-UiSettings { $script:txtSourceUrl.Text = [string]$script:SettingsManager.Get("LastSourceUrl", "") $script:txtTargetUrl.Text = [string]$script:SettingsManager.Get("LastTargetUrl", "") $script:txtOutputPath.Text = [string]$script:SettingsManager.Get("LastOutputPath", (Join-Path -Path (Get-Location).Path -ChildPath "SPMigrationOutput")) $script:txtMappingPath.Text = [string]$script:SettingsManager.Get("LastMappingTablePath", "") $script:MainForm.Width = [int]$script:SettingsManager.Get("WindowWidth", 1400) $script:MainForm.Height = [int]$script:SettingsManager.Get("WindowHeight", 940) Sync-MappingPathWithOutputPath -Force } function Load-ExistingMappingTableIfAvailable { $mappingPath = [string]$script:txtMappingPath.Text if ([string]::IsNullOrWhiteSpace($mappingPath)) { return } if (-not (Test-Path -LiteralPath $mappingPath)) { return } try { Load-MappingTableFromPath -Path $mappingPath } catch { Write-UILog -Message $_.Exception.Message -Level "WARN" } } function Invoke-LoadContainers { $sourceUrl = [string]$script:txtSourceUrl.Text if ([string]::IsNullOrWhiteSpace($sourceUrl)) { Show-UiMessage -Message "Bitte zuerst eine SourceUrl angeben." -Icon ([System.Windows.Forms.MessageBoxIcon]::Warning) return } $script:MainForm.UseWaitCursor = $true [System.Windows.Forms.Application]::DoEvents() try { Write-UILog -Message ("Lese Listen und Bibliotheken aus: {0}" -f $sourceUrl) $containers = Get-SourceContainers -SourceUrl $sourceUrl -IncludeHiddenLibraries:$script:chkIncludeHiddenLibraries.Checked -IncludeHiddenLists:$script:chkIncludeHiddenLists.Checked Populate-ContainerTree -Containers $containers Write-UILog -Message ("Container geladen. Bibliotheken und Listen gesamt: {0}" -f $containers.Count) } catch { Write-UILog -Message $_.Exception.Message -Level "ERROR" Show-UiMessage -Message $_.Exception.Message -Caption "Container konnten nicht geladen werden" -Icon ([System.Windows.Forms.MessageBoxIcon]::Error) } finally { $script:MainForm.UseWaitCursor = $false [System.Windows.Forms.Application]::DoEvents() } } function Invoke-ExportFromGui { try { $sourceUrl = [string]$script:txtSourceUrl.Text if ([string]::IsNullOrWhiteSpace($sourceUrl)) { throw "Bitte eine SourceUrl angeben." } $outputPath = Get-FullPathSafe -Path $script:txtOutputPath.Text if ([string]::IsNullOrWhiteSpace($outputPath)) { throw "Bitte einen OutputPath angeben." } if ((Get-SelectableContainerCount) -eq 0) { throw "Bitte zuerst die Quell-Listen und Bibliotheken laden." } $selectedContainerUrls = @(Get-SelectedContainerUrls) if ($selectedContainerUrls.Count -eq 0) { throw "Bitte mindestens eine Liste oder Bibliothek fuer den Export auswaehlen." } $script:txtOutputPath.Text = $outputPath Sync-MappingPathWithOutputPath -Force $parameters = @{ SourceUrl = $sourceUrl OutputPath = $outputPath Export = $true SelectedContainerUrls = $selectedContainerUrls } if ($script:chkIncludeHiddenLibraries.Checked) { $parameters.IncludeHiddenLibraries = $true } if ($script:chkIncludeHiddenLists.Checked) { $parameters.IncludeHiddenLists = $true } Invoke-MigrationScript -Parameters $parameters -ActionLabel "Export" $mappingPath = Join-Path -Path $outputPath -ChildPath "MappingTable.json" if (Test-Path -LiteralPath $mappingPath) { Load-MappingTableFromPath -Path $mappingPath $script:MainTabControl.SelectedTab = $script:tabMapping } } catch { Write-UILog -Message $_.Exception.Message -Level "ERROR" Show-UiMessage -Message $_.Exception.Message -Caption "Export fehlgeschlagen" -Icon ([System.Windows.Forms.MessageBoxIcon]::Error) } } function Invoke-ImportFromGui { try { $targetUrl = [string]$script:txtTargetUrl.Text if ([string]::IsNullOrWhiteSpace($targetUrl)) { throw "Bitte eine TargetUrl angeben." } $outputPath = Get-FullPathSafe -Path $script:txtOutputPath.Text if ([string]::IsNullOrWhiteSpace($outputPath)) { throw "Bitte einen OutputPath angeben." } $mappingPath = [string]$script:txtMappingPath.Text if ([string]::IsNullOrWhiteSpace($mappingPath)) { Sync-MappingPathWithOutputPath -Force $mappingPath = [string]$script:txtMappingPath.Text } if ([string]::IsNullOrWhiteSpace($mappingPath)) { throw "Bitte einen MappingTable-Pfad angeben." } Save-MappingTableToPath -Path $mappingPath $parameters = @{ TargetUrl = $targetUrl OutputPath = $outputPath Import = $true MappingTable = $mappingPath } if ($script:chkImportFiles.Checked) { $parameters.ImportFiles = $true } if ($script:chkImportLists.Checked) { $parameters.ImportLists = $true } if ($script:chkOverwrite.Checked) { $parameters.Overwrite = $true } Invoke-MigrationScript -Parameters $parameters -ActionLabel "Import" } catch { Write-UILog -Message $_.Exception.Message -Level "ERROR" Show-UiMessage -Message $_.Exception.Message -Caption "Import fehlgeschlagen" -Icon ([System.Windows.Forms.MessageBoxIcon]::Error) } } $formBuilder = [FormBuilder]::new("Start-SPMigration GUI") $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 $mainLayout = New-Object System.Windows.Forms.TableLayoutPanel $mainLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $mainLayout.RowCount = 3 $mainLayout.ColumnCount = 1 [void]$mainLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 110))) [void]$mainLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100))) [void]$mainLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 230))) $workspaceGroup = ([GroupBoxBuilder]::new("Arbeitsbereich")).Build() $workspaceLayout = New-Object System.Windows.Forms.TableLayoutPanel $workspaceLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $workspaceLayout.RowCount = 2 $workspaceLayout.ColumnCount = 4 [void]$workspaceLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 105))) [void]$workspaceLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100))) [void]$workspaceLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 110))) [void]$workspaceLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 110))) [void]$workspaceLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 36))) [void]$workspaceLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 36))) $lblOutputPath = ([LabelBuilder]::new("OutputPath")).SetTextAlign([System.Drawing.ContentAlignment]::MiddleLeft).Build() $lblOutputPath.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtOutputPath = New-Object System.Windows.Forms.TextBox $script:txtOutputPath.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtOutputPath.Margin = New-Object System.Windows.Forms.Padding(6) $btnBrowseOutputPath = ([ButtonBuilder]::new("Ordner...")).SetSize(95, 28).Build() $btnBrowseOutputPath.Margin = New-Object System.Windows.Forms.Padding(6) $btnSaveMappingGlobal = ([ButtonBuilder]::new("Speichern")).SetSize(95, 28).Build() $btnSaveMappingGlobal.Margin = New-Object System.Windows.Forms.Padding(6) $lblMappingPath = ([LabelBuilder]::new("MappingTable")).SetTextAlign([System.Drawing.ContentAlignment]::MiddleLeft).Build() $lblMappingPath.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtMappingPath = New-Object System.Windows.Forms.TextBox $script:txtMappingPath.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtMappingPath.Margin = New-Object System.Windows.Forms.Padding(6) $btnLoadMapping = ([ButtonBuilder]::new("Laden...")).SetSize(95, 28).Build() $btnLoadMapping.Margin = New-Object System.Windows.Forms.Padding(6) [void]$workspaceLayout.Controls.Add($lblOutputPath, 0, 0) [void]$workspaceLayout.Controls.Add($script:txtOutputPath, 1, 0) [void]$workspaceLayout.Controls.Add($btnBrowseOutputPath, 2, 0) [void]$workspaceLayout.Controls.Add($btnSaveMappingGlobal, 3, 0) [void]$workspaceLayout.Controls.Add($lblMappingPath, 0, 1) [void]$workspaceLayout.Controls.Add($script:txtMappingPath, 1, 1) [void]$workspaceLayout.Controls.Add($btnLoadMapping, 2, 1) $workspaceGroup.Controls.Add($workspaceLayout) $script:MainTabControl = ([TabControlBuilder]::new()).SetDock("Fill").Build() $script:tabExport = ([TabPageBuilder]::new("Export")).Build() $script:tabMapping = ([TabPageBuilder]::new("Mapping")).Build() $script:tabImport = ([TabPageBuilder]::new("Import")).Build() $script:MainTabControl.TabPages.AddRange(@($script:tabExport, $script:tabMapping, $script:tabImport)) $exportLayout = New-Object System.Windows.Forms.TableLayoutPanel $exportLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $exportLayout.RowCount = 3 $exportLayout.ColumnCount = 1 [void]$exportLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 116))) [void]$exportLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100))) [void]$exportLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 54))) $exportConfigGroup = ([GroupBoxBuilder]::new("Exportkonfiguration")).Build() $exportConfigLayout = New-Object System.Windows.Forms.TableLayoutPanel $exportConfigLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $exportConfigLayout.RowCount = 2 $exportConfigLayout.ColumnCount = 2 [void]$exportConfigLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 105))) [void]$exportConfigLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100))) [void]$exportConfigLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 34))) [void]$exportConfigLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 42))) $lblSourceUrl = ([LabelBuilder]::new("SourceUrl")).SetTextAlign([System.Drawing.ContentAlignment]::MiddleLeft).Build() $lblSourceUrl.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtSourceUrl = New-Object System.Windows.Forms.TextBox $script:txtSourceUrl.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtSourceUrl.Margin = New-Object System.Windows.Forms.Padding(6) $exportOptionsPanel = ([FlowLayoutPanelBuilder]::new()).SetDock("Fill").SetFlowDirection("LeftToRight").SetWrapContents($false).Build() $script:chkIncludeHiddenLibraries = New-Object System.Windows.Forms.CheckBox $script:chkIncludeHiddenLibraries.Text = "Hidden Libraries einbeziehen" $script:chkIncludeHiddenLibraries.AutoSize = $true $script:chkIncludeHiddenLibraries.Margin = New-Object System.Windows.Forms.Padding(6, 8, 18, 6) $script:chkIncludeHiddenLibraries.Font = New-Object System.Drawing.Font("Segoe UI", [single]$script:SettingsManager.Get("FontSize", 9)) $script:chkIncludeHiddenLists = New-Object System.Windows.Forms.CheckBox $script:chkIncludeHiddenLists.Text = "Hidden Lists einbeziehen" $script:chkIncludeHiddenLists.AutoSize = $true $script:chkIncludeHiddenLists.Margin = New-Object System.Windows.Forms.Padding(6, 8, 18, 6) $script:chkIncludeHiddenLists.Font = New-Object System.Drawing.Font("Segoe UI", [single]$script:SettingsManager.Get("FontSize", 9)) $exportOptionsHint = ([LabelBuilder]::new("Zuerst SourceUrl eintragen, dann die Container laden und gezielt auswaehlen.")).Build() $exportOptionsHint.Margin = New-Object System.Windows.Forms.Padding(6, 8, 6, 6) [void]$exportOptionsPanel.Controls.AddRange(@($script:chkIncludeHiddenLibraries, $script:chkIncludeHiddenLists, $exportOptionsHint)) [void]$exportConfigLayout.Controls.Add($lblSourceUrl, 0, 0) [void]$exportConfigLayout.Controls.Add($script:txtSourceUrl, 1, 0) [void]$exportConfigLayout.Controls.Add((New-Object System.Windows.Forms.Label), 0, 1) [void]$exportConfigLayout.Controls.Add($exportOptionsPanel, 1, 1) $exportConfigGroup.Controls.Add($exportConfigLayout) $containerSelectionGroup = ([GroupBoxBuilder]::new("Listen und Bibliotheken fuer den Export")).Build() $containerSelectionLayout = New-Object System.Windows.Forms.TableLayoutPanel $containerSelectionLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $containerSelectionLayout.RowCount = 1 $containerSelectionLayout.ColumnCount = 2 [void]$containerSelectionLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100))) [void]$containerSelectionLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 150))) $script:tvContainers = ([TreeViewBuilder]::new()).SetDock("Fill").SetCheckBoxes($true).Build() $containerButtonsPanel = New-Object System.Windows.Forms.FlowLayoutPanel $containerButtonsPanel.Dock = [System.Windows.Forms.DockStyle]::Fill $containerButtonsPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::TopDown $containerButtonsPanel.WrapContents = $false $containerButtonsPanel.AutoScroll = $true $btnSelectAllContainers = ([ButtonBuilder]::new("Alle markieren")).SetSize(126, 32).Build() $btnClearContainerSelection = ([ButtonBuilder]::new("Alle abwaehlen")).SetSize(126, 32).Build() [void]$containerButtonsPanel.Controls.AddRange(@($btnSelectAllContainers, $btnClearContainerSelection)) [void]$containerSelectionLayout.Controls.Add($script:tvContainers, 0, 0) [void]$containerSelectionLayout.Controls.Add($containerButtonsPanel, 1, 0) $containerSelectionGroup.Controls.Add($containerSelectionLayout) $exportActionsPanel = New-Object System.Windows.Forms.FlowLayoutPanel $exportActionsPanel.Dock = [System.Windows.Forms.DockStyle]::Fill $exportActionsPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft $exportActionsPanel.WrapContents = $false $btnRunExport = ([ButtonBuilder]::new("Export starten")).SetSize(150, 34).Build() $btnLoadContainers = ([ButtonBuilder]::new("Container laden")).SetSize(150, 34).Build() [void]$exportActionsPanel.Controls.AddRange(@($btnRunExport, $btnLoadContainers)) [void]$exportLayout.Controls.Add($exportConfigGroup, 0, 0) [void]$exportLayout.Controls.Add($containerSelectionGroup, 0, 1) [void]$exportLayout.Controls.Add($exportActionsPanel, 0, 2) $script:tabExport.Controls.Add($exportLayout) $mappingLayout = New-Object System.Windows.Forms.TableLayoutPanel $mappingLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $mappingLayout.RowCount = 2 $mappingLayout.ColumnCount = 1 [void]$mappingLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 34))) [void]$mappingLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100))) $mappingInfoLabel = ([LabelBuilder]::new("TargetTitle und TargetInternalName koennen hier direkt angepasst werden. Vor dem Import wird die MappingTable automatisch gespeichert.")).Build() $mappingInfoLabel.Dock = [System.Windows.Forms.DockStyle]::Fill $mappingTabs = ([TabControlBuilder]::new()).SetDock("Fill").Build() $libraryMappingTab = ([TabPageBuilder]::new("Bibliotheken")).Build() $listMappingTab = ([TabPageBuilder]::new("Listen")).Build() $systemColumnTab = ([TabPageBuilder]::new("System Columns")).Build() $customColumnTab = ([TabPageBuilder]::new("Custom Columns")).Build() $mappingTabs.TabPages.AddRange(@($libraryMappingTab, $listMappingTab, $systemColumnTab, $customColumnTab)) $script:gridLibraryMappings = ([DataGridViewBuilder]::new()).SetDock("Fill").SetAllowAddRows($false).Build() $script:gridListMappings = ([DataGridViewBuilder]::new()).SetDock("Fill").SetAllowAddRows($false).Build() $script:gridSystemColumns = ([DataGridViewBuilder]::new()).SetDock("Fill").SetAllowAddRows($false).Build() $script:gridCustomColumns = ([DataGridViewBuilder]::new()).SetDock("Fill").SetAllowAddRows($false).Build() Initialize-MappingTables Configure-MappingGrid -Grid $script:gridLibraryMappings -Table $script:LibraryMappingsTable -Schema $script:GridSchemas.LibraryMappings Configure-MappingGrid -Grid $script:gridListMappings -Table $script:ListMappingsTable -Schema $script:GridSchemas.ListMappings Configure-MappingGrid -Grid $script:gridSystemColumns -Table $script:SystemColumnsTable -Schema $script:GridSchemas.SystemColumns Configure-MappingGrid -Grid $script:gridCustomColumns -Table $script:CustomColumnsTable -Schema $script:GridSchemas.CustomColumns $libraryMappingTab.Controls.Add($script:gridLibraryMappings) $listMappingTab.Controls.Add($script:gridListMappings) $systemColumnTab.Controls.Add($script:gridSystemColumns) $customColumnTab.Controls.Add($script:gridCustomColumns) [void]$mappingLayout.Controls.Add($mappingInfoLabel, 0, 0) [void]$mappingLayout.Controls.Add($mappingTabs, 0, 1) $script:tabMapping.Controls.Add($mappingLayout) $importLayout = New-Object System.Windows.Forms.TableLayoutPanel $importLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $importLayout.RowCount = 3 $importLayout.ColumnCount = 1 [void]$importLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 122))) [void]$importLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 54))) [void]$importLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100))) $importConfigGroup = ([GroupBoxBuilder]::new("Importkonfiguration")).Build() $importConfigLayout = New-Object System.Windows.Forms.TableLayoutPanel $importConfigLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $importConfigLayout.RowCount = 2 $importConfigLayout.ColumnCount = 2 [void]$importConfigLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 105))) [void]$importConfigLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100))) [void]$importConfigLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 34))) [void]$importConfigLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 42))) $lblTargetUrl = ([LabelBuilder]::new("TargetUrl")).SetTextAlign([System.Drawing.ContentAlignment]::MiddleLeft).Build() $lblTargetUrl.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtTargetUrl = New-Object System.Windows.Forms.TextBox $script:txtTargetUrl.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtTargetUrl.Margin = New-Object System.Windows.Forms.Padding(6) $importOptionsPanel = ([FlowLayoutPanelBuilder]::new()).SetDock("Fill").SetFlowDirection("LeftToRight").SetWrapContents($false).Build() $script:chkImportFiles = New-Object System.Windows.Forms.CheckBox $script:chkImportFiles.Text = "Dateien/Bibliotheken importieren" $script:chkImportFiles.AutoSize = $true $script:chkImportFiles.Margin = New-Object System.Windows.Forms.Padding(6, 8, 18, 6) $script:chkImportFiles.Font = New-Object System.Drawing.Font("Segoe UI", [single]$script:SettingsManager.Get("FontSize", 9)) $script:chkImportLists = New-Object System.Windows.Forms.CheckBox $script:chkImportLists.Text = "Listen importieren" $script:chkImportLists.AutoSize = $true $script:chkImportLists.Margin = New-Object System.Windows.Forms.Padding(6, 8, 18, 6) $script:chkImportLists.Font = New-Object System.Drawing.Font("Segoe UI", [single]$script:SettingsManager.Get("FontSize", 9)) $script:chkOverwrite = New-Object System.Windows.Forms.CheckBox $script:chkOverwrite.Text = "Overwrite" $script:chkOverwrite.AutoSize = $true $script:chkOverwrite.Margin = New-Object System.Windows.Forms.Padding(6, 8, 18, 6) $script:chkOverwrite.Font = New-Object System.Drawing.Font("Segoe UI", [single]$script:SettingsManager.Get("FontSize", 9)) $importHintLabel = ([LabelBuilder]::new("Wenn weder ImportFiles noch ImportLists gesetzt sind, verarbeitet das Skript beides.")).Build() $importHintLabel.Margin = New-Object System.Windows.Forms.Padding(6, 8, 6, 6) [void]$importOptionsPanel.Controls.AddRange(@($script:chkImportFiles, $script:chkImportLists, $script:chkOverwrite, $importHintLabel)) [void]$importConfigLayout.Controls.Add($lblTargetUrl, 0, 0) [void]$importConfigLayout.Controls.Add($script:txtTargetUrl, 1, 0) [void]$importConfigLayout.Controls.Add((New-Object System.Windows.Forms.Label), 0, 1) [void]$importConfigLayout.Controls.Add($importOptionsPanel, 1, 1) $importConfigGroup.Controls.Add($importConfigLayout) $importActionsPanel = New-Object System.Windows.Forms.FlowLayoutPanel $importActionsPanel.Dock = [System.Windows.Forms.DockStyle]::Fill $importActionsPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft $importActionsPanel.WrapContents = $false $btnRunImport = ([ButtonBuilder]::new("Import starten")).SetSize(150, 34).Build() [void]$importActionsPanel.Controls.Add($btnRunImport) $importNoteLabel = ([LabelBuilder]::new("Die aktuell in der GUI sichtbaren Mapping-Aenderungen werden vor dem Import in die JSON-Datei geschrieben.")).Build() $importNoteLabel.Dock = [System.Windows.Forms.DockStyle]::Top [void]$importLayout.Controls.Add($importConfigGroup, 0, 0) [void]$importLayout.Controls.Add($importActionsPanel, 0, 1) [void]$importLayout.Controls.Add($importNoteLabel, 0, 2) $script:tabImport.Controls.Add($importLayout) $logGroup = ([GroupBoxBuilder]::new("Log")).Build() $logLayout = New-Object System.Windows.Forms.TableLayoutPanel $logLayout.Dock = [System.Windows.Forms.DockStyle]::Fill $logLayout.RowCount = 2 $logLayout.ColumnCount = 1 [void]$logLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 40))) [void]$logLayout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100))) $logButtonsPanel = New-Object System.Windows.Forms.FlowLayoutPanel $logButtonsPanel.Dock = [System.Windows.Forms.DockStyle]::Fill $logButtonsPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft $logButtonsPanel.WrapContents = $false $btnClearLog = ([ButtonBuilder]::new("Log leeren")).SetSize(120, 28).Build() [void]$logButtonsPanel.Controls.Add($btnClearLog) $script:txtLog = New-Object System.Windows.Forms.TextBox $script:txtLog.Dock = [System.Windows.Forms.DockStyle]::Fill $script:txtLog.Multiline = $true $script:txtLog.ReadOnly = $true $script:txtLog.ScrollBars = [System.Windows.Forms.ScrollBars]::Vertical $script:txtLog.WordWrap = $false $script:txtLog.Font = New-Object System.Drawing.Font("Consolas", 9) [void]$logLayout.Controls.Add($logButtonsPanel, 0, 0) [void]$logLayout.Controls.Add($script:txtLog, 0, 1) $logGroup.Controls.Add($logLayout) [void]$mainLayout.Controls.Add($workspaceGroup, 0, 0) [void]$mainLayout.Controls.Add($script:MainTabControl, 0, 1) [void]$mainLayout.Controls.Add($logGroup, 0, 2) $script:MainForm.Controls.Add($mainLayout) $btnBrowseOutputPath.Add_Click({ $dialog = [DialogBuilder]::SelectFolder().SetTitle("OutputPath waehlen").SetSelectedPath((Get-ParentDirectorySafe -Path $script:txtOutputPath.Text)) if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { $script:txtOutputPath.Text = (Get-FullPathSafe -Path $dialog.GetPath()) Sync-MappingPathWithOutputPath -Force } }) $btnSaveMappingGlobal.Add_Click({ try { $currentMappingPath = [string]$script:txtMappingPath.Text $dialog = [DialogBuilder]::SaveFile().SetTitle("MappingTable speichern").SetFilter("JSON (*.json)|*.json|Alle Dateien (*.*)|*.*").SetOverwritePrompt($true) if (-not [string]::IsNullOrWhiteSpace($currentMappingPath)) { $dialog.SetInitialDirectory((Get-ParentDirectorySafe -Path $currentMappingPath)) | Out-Null $dialog.SetFileName([System.IO.Path]::GetFileName($currentMappingPath)) | Out-Null } if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { Save-MappingTableToPath -Path $dialog.GetPath() } } catch { Write-UILog -Message $_.Exception.Message -Level "ERROR" Show-UiMessage -Message $_.Exception.Message -Caption "MappingTable konnte nicht gespeichert werden" -Icon ([System.Windows.Forms.MessageBoxIcon]::Error) } }) $btnLoadMapping.Add_Click({ try { $dialog = [DialogBuilder]::OpenFile().SetTitle("MappingTable laden").SetFilter("JSON (*.json)|*.json|Alle Dateien (*.*)|*.*").SetCheckFileExists($true) $initialDirectory = Get-ParentDirectorySafe -Path $script:txtMappingPath.Text if ([string]::IsNullOrWhiteSpace($initialDirectory)) { $initialDirectory = Get-ParentDirectorySafe -Path $script:txtOutputPath.Text } if (-not [string]::IsNullOrWhiteSpace($initialDirectory)) { $dialog.SetInitialDirectory($initialDirectory) | Out-Null } if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { Load-MappingTableFromPath -Path $dialog.GetPath() $script:MainTabControl.SelectedTab = $script:tabMapping } } catch { Write-UILog -Message $_.Exception.Message -Level "ERROR" Show-UiMessage -Message $_.Exception.Message -Caption "MappingTable konnte nicht geladen werden" -Icon ([System.Windows.Forms.MessageBoxIcon]::Error) } }) $script:tvContainers.Add_AfterCheck({ param($sender, $e) if ($script:IsUpdatingContainerChecks) { return } $script:IsUpdatingContainerChecks = $true try { if ($e.Node.Level -eq 0) { Set-TreeChildrenChecked -Node $e.Node -Checked $e.Node.Checked } else { Update-ParentNodeCheckedState -Node $e.Node } } finally { $script:IsUpdatingContainerChecks = $false } }) $btnSelectAllContainers.Add_Click({ Set-AllContainerNodesChecked -Checked $true }) $btnClearContainerSelection.Add_Click({ Set-AllContainerNodesChecked -Checked $false }) $btnLoadContainers.Add_Click({ Invoke-LoadContainers }) $btnRunExport.Add_Click({ Invoke-ExportFromGui }) $btnRunImport.Add_Click({ Invoke-ImportFromGui }) $btnClearLog.Add_Click({ $script:txtLog.Clear() }) $script:txtOutputPath.Add_Leave({ Sync-MappingPathWithOutputPath }) $script:txtOutputPath.Add_TextChanged({ if ([string]::IsNullOrWhiteSpace($script:txtOutputPath.Text)) { return } Sync-MappingPathWithOutputPath }) $script:MainForm.Add_Shown({ Write-UILog -Message "Start-SPMigration GUI gestartet." Load-UiSettings Set-MappingTableToUi -MappingTable (New-EmptyMappingTable) Load-ExistingMappingTableIfAvailable $formBuilder.RegisterAllAccessibleControls() | Out-Null }) $script:MainForm.Add_FormClosing({ Save-UiSettings }) [void]$script:txtSourceUrl.Focus() if ($NoGui.IsPresent) { return } $formBuilder.Show()