Files
Start-SPMigration/Start-SPMigrationGUI.ps1
2026-04-16 19:19:24 +02:00

2212 lines
76 KiB
PowerShell

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"
$script:ApplicationDataRoot = Join-Path -Path (Split-Path -Parent $PSCommandPath) -ChildPath ".gui-state"
class SettingsManager {
[string]$SettingsPath
[hashtable]$Settings = @{}
SettingsManager([string]$AppName) {
$appRoot = if ([string]::IsNullOrWhiteSpace($script:ApplicationDataRoot)) {
[Environment]::GetFolderPath("ApplicationData")
}
else {
$script:ApplicationDataRoot
}
$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 = if ([string]::IsNullOrWhiteSpace($script:ApplicationDataRoot)) {
[Environment]::GetFolderPath("ApplicationData")
}
else {
$script:ApplicationDataRoot
}
$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()
[System.Windows.Forms.Application]::SetCompatibleTextRenderingDefault($false)
$script:SettingsManager = [SettingsManager]::new("Start-SPMigration")
$script:LogManager = [LogManager]::new("Start-SPMigration")
[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()