ui/splitterui.ps1
|
using namespace GliderUI using namespace GliderUI.Avalonia using namespace GliderUI.Avalonia.Controls using namespace GliderUI.Avalonia.Platform.Storage function New-SplitterUiWindow { [CmdletBinding()] param() $win = [Window]::new() $win.ExtendClientAreaToDecorationsHint = $true $win.ExtendClientAreaTitleBarHeightHint = 40 $win.Title = 'Splitter UI' $win.Width = 1220 $win.Height = 860 $win.MinWidth = 980 $win.MinHeight = 700 $accentColor = [GliderUI.Avalonia.Media.Brush]::Parse('#3AA0FF') $panelColor = [GliderUI.Avalonia.Media.Brush]::Parse('#1A1E26') $mutedTextColor = [GliderUI.Avalonia.Media.Brush]::Parse('#A9B4C4') $textOnAccentColor = [GliderUI.Avalonia.Media.Brush]::Parse('#FFFFFF') $rootGrid = [Grid]::new() # Keep content below the extended title bar region to avoid visual overlap. $rootGrid.Margin = [Thickness]::new(12, 44, 12, 12) $rootGrid.RowSpacing = 10 $rootGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $rootGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $rootGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) $rootGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $headerGrid = [Grid]::new() $headerGrid.ColumnSpacing = 8 $headerGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1, 'Star'))) $headerTextStack = [StackPanel]::new() $headerTextStack.Orientation = 'Vertical' $headerTextStack.Spacing = 2 $titleText = [TextBlock]::new() $titleText.FontSize = 22 $titleText.FontWeight = 'SemiBold' $titleText.Text = 'Splitter' $subtitleText = [TextBlock]::new() $subtitleText.Text = 'Edition-aware Windows install media builder' $subtitleText.Foreground = $mutedTextColor $headerTextStack.Children.Add($titleText) $headerTextStack.Children.Add($subtitleText) $headerGrid.Children.Add($headerTextStack) [Grid]::SetRow($headerGrid, 0) $statusText = [TextBlock]::new() $statusText.Text = 'Preflight has not run.' $statusText.Foreground = $mutedTextColor [Grid]::SetRow($statusText, 1) $shellGrid = [Grid]::new() $shellGrid.ColumnSpacing = 10 $shellGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(230))) $shellGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1, 'Star'))) [Grid]::SetRow($shellGrid, 2) $navGrid = [Grid]::new() $navGrid.RowSpacing = 10 $navGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $navGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $navGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) $navHeader = [TextBlock]::new() $navHeader.FontSize = 16 $navHeader.FontWeight = 'SemiBold' $navHeader.Text = 'Workflows' $navHeader.Foreground = $accentColor $navHintText = [TextBlock]::new() $navHintText.Text = 'Choose a stage for source, split, service, build, or outputs.' $navHintText.TextWrapping = 'Wrap' $navHintText.Foreground = $mutedTextColor $navHintText.FontSize = 12 [Grid]::SetRow($navHintText, 1) $navListBox = [ListBox]::new() $navListBox.MinWidth = 200 $navListBox.Background = $panelColor [Grid]::SetRow($navListBox, 2) $navItems = @( @{ Label = 'Source Media'; Tooltip = 'Select source ISO, run preflight checks, and discover install images.' } @{ Label = 'Split Editions'; Tooltip = 'Choose editions and naming options, then run split operations.' } @{ Label = 'Image Servicing'; Tooltip = 'Add drivers, packages, unattend files, and payload files to media.' } @{ Label = 'Build Outputs'; Tooltip = 'Build bootable ISO files or export selected indexes to a new WIM.' } ) foreach ($navItem in $navItems) { $navListItem = [ListBoxItem]::new() $navListItem.Content = $navItem.Label [GliderUI.Avalonia.Controls.ToolTip]::SetTip($navListItem, $navItem.Tooltip) $navListBox.Items.Add($navListItem) | Out-Null } $navGrid.Children.Add($navHeader) $navGrid.Children.Add($navHintText) $navGrid.Children.Add($navListBox) $pageHostGrid = [Grid]::new() [Grid]::SetColumn($pageHostGrid, 1) $leftGrid = [Grid]::new() $leftGrid.RowSpacing = 8 $leftGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $leftGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $leftGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $optionsHeader = [TextBlock]::new() $optionsHeader.FontSize = 16 $optionsHeader.FontWeight = 'SemiBold' $optionsHeader.Text = 'Build Options' $checkStack = [StackPanel]::new() $checkStack.Spacing = 8 [Grid]::SetRow($checkStack, 1) $skipBootableIsoCheckBox = [CheckBox]::new() $skipBootableIsoCheckBox.Content = 'Skip bootable ISO build' $desktopExperienceCheckBox = [CheckBox]::new() $desktopExperienceCheckBox.Content = 'Desktop Experience only' $serverCoreCheckBox = [CheckBox]::new() $serverCoreCheckBox.Content = 'Server Core only' $checkStack.Children.Add($skipBootableIsoCheckBox) $checkStack.Children.Add($desktopExperienceCheckBox) $checkStack.Children.Add($serverCoreCheckBox) $runSplitButton = [Button]::new() $runSplitButton.Height = 34 $runSplitButton.Content = 'Run Split' $runSplitButton.Background = $accentColor $runSplitButton.Foreground = $textOnAccentColor [Grid]::SetRow($runSplitButton, 2) $leftGrid.Children.Add($optionsHeader) $leftGrid.Children.Add($checkStack) $leftGrid.Children.Add($runSplitButton) $rightGrid = [Grid]::new() $rightGrid.RowSpacing = 10 $rightGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $rightGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) $rightGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) [Grid]::SetColumn($rightGrid, 1) $inputGrid = [Grid]::new() $inputGrid.ColumnSpacing = 8 $inputGrid.RowSpacing = 6 $inputGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $inputGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $inputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1.7, 'Star'))) $inputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2, 'Star'))) $inputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2, 'Star'))) $inputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1.4, 'Star'))) $inputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1.1, 'Star'))) $editionNamesLabel = [TextBlock]::new(); $editionNamesLabel.Text = 'Edition names'; [Grid]::SetColumn($editionNamesLabel, 0); [Grid]::SetRow($editionNamesLabel, 0) $workingRootLabel = [TextBlock]::new(); $workingRootLabel.Text = 'Working root'; [Grid]::SetColumn($workingRootLabel, 1); [Grid]::SetRow($workingRootLabel, 0) $outputRootLabel = [TextBlock]::new(); $outputRootLabel.Text = 'Output root'; [Grid]::SetColumn($outputRootLabel, 2); [Grid]::SetRow($outputRootLabel, 0) $outputBaseLabel = [TextBlock]::new(); $outputBaseLabel.Text = 'Output base'; [Grid]::SetColumn($outputBaseLabel, 3); [Grid]::SetRow($outputBaseLabel, 0) $labelPrefixLabel = [TextBlock]::new(); $labelPrefixLabel.Text = 'Label prefix'; [Grid]::SetColumn($labelPrefixLabel, 4); [Grid]::SetRow($labelPrefixLabel, 0) $editionNamesTextBox = [TextBox]::new(); $editionNamesTextBox.Watermark = 'Standard,Datacenter'; [Grid]::SetColumn($editionNamesTextBox, 0); [Grid]::SetRow($editionNamesTextBox, 1) $workingRootTextBox = [TextBox]::new(); $workingRootTextBox.Watermark = 'C:\work\splitter'; [Grid]::SetColumn($workingRootTextBox, 1); [Grid]::SetRow($workingRootTextBox, 1) $outputRootTextBox = [TextBox]::new(); $outputRootTextBox.Watermark = 'C:\out\splitter'; [Grid]::SetColumn($outputRootTextBox, 2); [Grid]::SetRow($outputRootTextBox, 1) $outputBaseNameTextBox = [TextBox]::new(); $outputBaseNameTextBox.Watermark = 'WinServer_2025'; [Grid]::SetColumn($outputBaseNameTextBox, 3); [Grid]::SetRow($outputBaseNameTextBox, 1) $labelPrefixTextBox = [TextBox]::new(); $labelPrefixTextBox.Text = 'WIN'; [Grid]::SetColumn($labelPrefixTextBox, 4); [Grid]::SetRow($labelPrefixTextBox, 1) $inputGrid.Children.Add($editionNamesLabel) $inputGrid.Children.Add($workingRootLabel) $inputGrid.Children.Add($outputRootLabel) $inputGrid.Children.Add($outputBaseLabel) $inputGrid.Children.Add($labelPrefixLabel) $inputGrid.Children.Add($editionNamesTextBox) $inputGrid.Children.Add($workingRootTextBox) $inputGrid.Children.Add($outputRootTextBox) $inputGrid.Children.Add($outputBaseNameTextBox) $inputGrid.Children.Add($labelPrefixTextBox) $sourceIsoTextBox = [TextBox]::new() $sourceIsoTextBox.Watermark = 'C:\ISO\Windows.iso' $browseSourceIsoButton = [Button]::new() $browseSourceIsoButton.Width = 82 $browseSourceIsoButton.Content = 'Browse' $runPreflightButton = [Button]::new() $runPreflightButton.Width = 130 $runPreflightButton.Height = 32 $runPreflightButton.Content = 'Run Preflight' $runPreflightButton.Background = $accentColor $runPreflightButton.Foreground = $textOnAccentColor $discoverImagesButton = [Button]::new() $discoverImagesButton.Height = 32 $discoverImagesButton.Content = 'Discover Source Images' $discoverImagesButton.Background = $accentColor $discoverImagesButton.Foreground = $textOnAccentColor $imagesHeader = [TextBlock]::new() $imagesHeader.FontWeight = 'SemiBold' $imagesHeader.Text = 'Discovered source images' $imagesListBox = [ListBox]::new() $executionGrid = [Grid]::new() $executionGrid.RowSpacing = 8 $executionGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $executionGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) [Grid]::SetRow($executionGrid, 1) $executionHeader = [TextBlock]::new() $executionHeader.FontSize = 16 $executionHeader.FontWeight = 'SemiBold' $executionHeader.Text = 'Execution' $logTextBox = [TextBox]::new() $logTextBox.AcceptsReturn = $true $logTextBox.IsReadOnly = $true $logTextBox.TextWrapping = 'NoWrap' $logTextBox.IsUndoEnabled = $false $logTextBox.FontFamily = 'Cascadia Mono' $logTextBox.Padding = [Thickness]::new(8, 6, 8, 30) [Grid]::SetRow($logTextBox, 1) $executionGrid.Children.Add($executionHeader) $executionGrid.Children.Add($logTextBox) $resultsGrid = [Grid]::new() $resultsGrid.RowSpacing = 8 $resultsGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $resultsGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) [Grid]::SetRow($resultsGrid, 2) $resultsHeader = [TextBlock]::new() $resultsHeader.FontSize = 16 $resultsHeader.FontWeight = 'SemiBold' $resultsHeader.Text = 'Latest results' $resultsListBox = [ListBox]::new() [Grid]::SetRow($resultsListBox, 1) $resultsGrid.Children.Add($resultsHeader) $resultsGrid.Children.Add($resultsListBox) $rightGrid.Children.Add($inputGrid) $rightGrid.Children.Add($executionGrid) $rightGrid.Children.Add($resultsGrid) $splitPageGrid = [Grid]::new() $splitPageGrid.RowSpacing = 10 $splitPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $splitPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $splitPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) $splitTitle = [TextBlock]::new() $splitTitle.FontSize = 18 $splitTitle.FontWeight = 'SemiBold' $splitTitle.Text = 'Split' $splitHintText = [TextBlock]::new() $splitHintText.Text = 'Configure output naming and flavor options, then run split and review logs and results.' $splitHintText.TextWrapping = 'Wrap' [Grid]::SetRow($splitHintText, 1) $splitContentGrid = [Grid]::new() $splitContentGrid.ColumnSpacing = 10 $splitContentGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(300))) $splitContentGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1, 'Star'))) [Grid]::SetRow($splitContentGrid, 2) $splitContentGrid.Children.Add($leftGrid) $splitContentGrid.Children.Add($rightGrid) $splitPageGrid.Children.Add($splitTitle) $splitPageGrid.Children.Add($splitHintText) $splitPageGrid.Children.Add($splitContentGrid) $mediaPageGrid = [Grid]::new() $mediaPageGrid.RowSpacing = 10 $mediaPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(140))) $mediaPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) $mediaTitle = [TextBlock]::new() $mediaTitle.FontSize = 18 $mediaTitle.FontWeight = 'SemiBold' $mediaTitle.Text = 'Source Media' $mediaInputGrid = [Grid]::new() $mediaInputGrid.ColumnSpacing = 8 $mediaInputGrid.RowSpacing = 6 $mediaInputGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaInputGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaInputGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $mediaInputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1, 'Star'))) $mediaInputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::Auto)) $mediaInputGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::Auto)) [Grid]::SetRow($mediaInputGrid, 1) $sourceIsoLabel = [TextBlock]::new() $sourceIsoLabel.Text = 'Source ISO' [Grid]::SetColumn($sourceIsoLabel, 0) [Grid]::SetRow($sourceIsoLabel, 0) $sourceIsoContainer = [Grid]::new() $sourceIsoContainer.ColumnSpacing = 6 $sourceIsoContainer.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1, 'Star'))) $sourceIsoContainer.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::Auto)) [Grid]::SetColumn($sourceIsoContainer, 0) [Grid]::SetRow($sourceIsoContainer, 1) [Grid]::SetColumn($browseSourceIsoButton, 1) $sourceIsoContainer.Children.Add($sourceIsoTextBox) $sourceIsoContainer.Children.Add($browseSourceIsoButton) [Grid]::SetColumn($runPreflightButton, 1) [Grid]::SetRow($runPreflightButton, 1) [Grid]::SetColumn($discoverImagesButton, 2) [Grid]::SetRow($discoverImagesButton, 1) $mediaHintText = [TextBlock]::new() $mediaHintText.Text = 'Run preflight before discovery to catch ADK, DISM, and source path issues early.' $mediaHintText.TextWrapping = 'Wrap' [Grid]::SetColumnSpan($mediaHintText, 3) [Grid]::SetRow($mediaHintText, 2) $mediaInputGrid.Children.Add($sourceIsoLabel) $mediaInputGrid.Children.Add($sourceIsoContainer) $mediaInputGrid.Children.Add($runPreflightButton) $mediaInputGrid.Children.Add($discoverImagesButton) $mediaInputGrid.Children.Add($mediaHintText) $mediaLogHeader = [TextBlock]::new() $mediaLogHeader.FontWeight = 'SemiBold' $mediaLogHeader.Text = 'Media activity' $mediaLogHeader.Foreground = $accentColor [Grid]::SetRow($mediaLogHeader, 2) $mediaLogTextBox = [TextBox]::new() $mediaLogTextBox.AcceptsReturn = $true $mediaLogTextBox.IsReadOnly = $true $mediaLogTextBox.TextWrapping = 'NoWrap' $mediaLogTextBox.IsUndoEnabled = $false $mediaLogTextBox.FontFamily = 'Cascadia Mono' $mediaLogTextBox.Padding = [Thickness]::new(8, 6, 8, 30) $mediaLogTextBox.MinHeight = 148 $mediaLogTextBox.Background = $panelColor [Grid]::SetRow($mediaLogTextBox, 3) [Grid]::SetRow($imagesHeader, 4) [Grid]::SetRow($imagesListBox, 6) $mediaPageGrid.Children.Add($mediaTitle) $mediaPageGrid.Children.Add($mediaInputGrid) $mediaPageGrid.Children.Add($mediaLogHeader) $mediaPageGrid.Children.Add($mediaLogTextBox) $mediaPageGrid.Children.Add($imagesHeader) $mediaPageGrid.Children.Add($imagesListBox) $servicingPageGrid = [Grid]::new() $servicingPageGrid.RowSpacing = 10 $servicingPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(130))) $servicingPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) $servicingTitle = [TextBlock]::new() $servicingTitle.FontSize = 18 $servicingTitle.FontWeight = 'SemiBold' $servicingTitle.Text = 'Servicing' $servicingHintText = [TextBlock]::new() $servicingHintText.Text = 'Apply drivers, packages, and unattend to an extracted media root.' $servicingHintText.TextWrapping = 'Wrap' [Grid]::SetRow($servicingHintText, 1) $servicingFormGrid = [Grid]::new() $servicingFormGrid.ColumnSpacing = 8 $servicingFormGrid.RowSpacing = 6 $servicingFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $servicingFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2.2, 'Star'))) $servicingFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2, 'Star'))) $servicingFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2, 'Star'))) $servicingFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1.3, 'Star'))) $servicingFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1.5, 'Star'))) [Grid]::SetRow($servicingFormGrid, 2) $serviceMediaRootLabel = [TextBlock]::new(); $serviceMediaRootLabel.Text = 'Media root'; [Grid]::SetColumn($serviceMediaRootLabel, 0); [Grid]::SetRow($serviceMediaRootLabel, 0) $driverPathLabel = [TextBlock]::new(); $driverPathLabel.Text = 'Driver path'; [Grid]::SetColumn($driverPathLabel, 1); [Grid]::SetRow($driverPathLabel, 0) $packagePathLabel = [TextBlock]::new(); $packagePathLabel.Text = 'Package path'; [Grid]::SetColumn($packagePathLabel, 2); [Grid]::SetRow($packagePathLabel, 0) $serviceIndexesLabel = [TextBlock]::new(); $serviceIndexesLabel.Text = 'Indexes'; [Grid]::SetColumn($serviceIndexesLabel, 3); [Grid]::SetRow($serviceIndexesLabel, 0) $unattendPathLabel = [TextBlock]::new(); $unattendPathLabel.Text = 'Unattend XML'; [Grid]::SetColumn($unattendPathLabel, 4); [Grid]::SetRow($unattendPathLabel, 0) $serviceMediaRootTextBox = [TextBox]::new(); $serviceMediaRootTextBox.Watermark = 'C:\work\splitter\Standard'; [Grid]::SetColumn($serviceMediaRootTextBox, 0); [Grid]::SetRow($serviceMediaRootTextBox, 1) $driverPathTextBox = [TextBox]::new(); $driverPathTextBox.Watermark = 'C:\drivers\net' $packagePathTextBox = [TextBox]::new(); $packagePathTextBox.Watermark = 'C:\updates\kb.cab' $serviceIndexesTextBox = [TextBox]::new(); $serviceIndexesTextBox.Watermark = '1,2'; [Grid]::SetColumn($serviceIndexesTextBox, 3); [Grid]::SetRow($serviceIndexesTextBox, 1) $unattendPathTextBox = [TextBox]::new(); $unattendPathTextBox.Watermark = 'C:\answer\autounattend.xml' $serviceOptionsStack = [StackPanel]::new() $serviceOptionsStack.Orientation = 'Horizontal' $serviceOptionsStack.Spacing = 12 [Grid]::SetColumnSpan($serviceOptionsStack, 5) [Grid]::SetRow($serviceOptionsStack, 2) $serviceRecurseDriversCheckBox = [CheckBox]::new(); $serviceRecurseDriversCheckBox.Content = 'Recurse drivers' $serviceForceUnsignedDriversCheckBox = [CheckBox]::new(); $serviceForceUnsignedDriversCheckBox.Content = 'Force unsigned drivers' $serviceIgnoreCheckCheckBox = [CheckBox]::new(); $serviceIgnoreCheckCheckBox.Content = 'Ignore package check' $servicePreventPendingCheckBox = [CheckBox]::new(); $servicePreventPendingCheckBox.Content = 'Prevent pending packages' $serviceOptionsStack.Children.Add($serviceRecurseDriversCheckBox) $serviceOptionsStack.Children.Add($serviceForceUnsignedDriversCheckBox) $serviceOptionsStack.Children.Add($serviceIgnoreCheckCheckBox) $serviceOptionsStack.Children.Add($servicePreventPendingCheckBox) $unattendDestinationLabel = [TextBlock]::new(); $unattendDestinationLabel.Text = 'Unattend destination'; [Grid]::SetColumn($unattendDestinationLabel, 0); [Grid]::SetRow($unattendDestinationLabel, 3) $unattendDestinationTextBox = [TextBox]::new(); $unattendDestinationTextBox.Text = 'autounattend.xml'; [Grid]::SetColumn($unattendDestinationTextBox, 1); [Grid]::SetColumnSpan($unattendDestinationTextBox, 2); [Grid]::SetRow($unattendDestinationTextBox, 3) $servicingActionsStack = [StackPanel]::new() $servicingActionsStack.Orientation = 'Horizontal' $servicingActionsStack.Spacing = 8 [Grid]::SetColumn($servicingActionsStack, 3) [Grid]::SetColumnSpan($servicingActionsStack, 2) [Grid]::SetRow($servicingActionsStack, 3) $addDriverButton = [Button]::new(); $addDriverButton.Height = 32; $addDriverButton.Content = 'Add Driver' $addPackageButton = [Button]::new(); $addPackageButton.Height = 32; $addPackageButton.Content = 'Add Package' $addUnattendButton = [Button]::new(); $addUnattendButton.Height = 32; $addUnattendButton.Content = 'Add Unattend' $addPayloadFileButton = [Button]::new(); $addPayloadFileButton.Height = 32; $addPayloadFileButton.Content = 'Add Payload File' $addDriverButton.Background = $accentColor; $addDriverButton.Foreground = $textOnAccentColor $addPackageButton.Background = $accentColor; $addPackageButton.Foreground = $textOnAccentColor $addUnattendButton.Background = $accentColor; $addUnattendButton.Foreground = $textOnAccentColor $addPayloadFileButton.Background = $accentColor; $addPayloadFileButton.Foreground = $textOnAccentColor $payloadSourceTextBox = [TextBox]::new() $payloadSourceTextBox.Watermark = 'D:\Packages\PowerShell-7.6.3-win-x64.msi' $payloadDestinationTextBox = [TextBox]::new() $payloadDestinationTextBox.Text = 'sources\$OEM$\$1\Install\PowerShell-7.6.3-win-x64.msi' [Grid]::SetColumn($driverPathTextBox, 1) [Grid]::SetRow($driverPathTextBox, 1) [Grid]::SetColumn($packagePathTextBox, 2) [Grid]::SetRow($packagePathTextBox, 1) [Grid]::SetColumn($unattendPathTextBox, 4) [Grid]::SetRow($unattendPathTextBox, 1) $servicingActionsStack.Children.Add($addDriverButton) $servicingActionsStack.Children.Add($addPackageButton) $servicingActionsStack.Children.Add($addUnattendButton) [Grid]::SetColumn($payloadSourceTextBox, 0) [Grid]::SetColumnSpan($payloadSourceTextBox, 3) [Grid]::SetRow($payloadSourceTextBox, 4) [Grid]::SetColumn($payloadDestinationTextBox, 3) [Grid]::SetRow($payloadDestinationTextBox, 4) [Grid]::SetColumn($addPayloadFileButton, 4) [Grid]::SetRow($addPayloadFileButton, 4) $servicingFormGrid.Children.Add($serviceMediaRootLabel) $servicingFormGrid.Children.Add($driverPathLabel) $servicingFormGrid.Children.Add($packagePathLabel) $servicingFormGrid.Children.Add($serviceIndexesLabel) $servicingFormGrid.Children.Add($unattendPathLabel) $servicingFormGrid.Children.Add($serviceMediaRootTextBox) $servicingFormGrid.Children.Add($driverPathTextBox) $servicingFormGrid.Children.Add($packagePathTextBox) $servicingFormGrid.Children.Add($serviceIndexesTextBox) $servicingFormGrid.Children.Add($unattendPathTextBox) $servicingFormGrid.Children.Add($serviceOptionsStack) $servicingFormGrid.Children.Add($unattendDestinationLabel) $servicingFormGrid.Children.Add($unattendDestinationTextBox) $servicingFormGrid.Children.Add($servicingActionsStack) $servicingFormGrid.Children.Add($payloadSourceTextBox) $servicingFormGrid.Children.Add($payloadDestinationTextBox) $servicingFormGrid.Children.Add($addPayloadFileButton) $servicingLogHeader = [TextBlock]::new() $servicingLogHeader.FontWeight = 'SemiBold' $servicingLogHeader.Text = 'Servicing activity' $servicingLogHeader.Foreground = $accentColor [Grid]::SetRow($servicingLogHeader, 3) $servicingLogTextBox = [TextBox]::new() $servicingLogTextBox.AcceptsReturn = $true $servicingLogTextBox.IsReadOnly = $true $servicingLogTextBox.TextWrapping = 'NoWrap' $servicingLogTextBox.IsUndoEnabled = $false $servicingLogTextBox.FontFamily = 'Cascadia Mono' $servicingLogTextBox.Padding = [Thickness]::new(8, 6, 8, 30) [Grid]::SetRow($servicingLogTextBox, 4) $servicingSelectionHeader = [TextBlock]::new() $servicingSelectionHeader.FontWeight = 'SemiBold' $servicingSelectionHeader.Text = 'Selected and added items' $servicingSelectionHeader.Foreground = $accentColor [Grid]::SetRow($servicingSelectionHeader, 5) $servicingSelectionsListBox = [ListBox]::new() [Grid]::SetRow($servicingSelectionsListBox, 6) $servicingPageGrid.Children.Add($servicingTitle) $servicingPageGrid.Children.Add($servicingHintText) $servicingPageGrid.Children.Add($servicingFormGrid) $servicingPageGrid.Children.Add($servicingLogHeader) $servicingPageGrid.Children.Add($servicingLogTextBox) $servicingPageGrid.Children.Add($servicingSelectionHeader) $servicingPageGrid.Children.Add($servicingSelectionsListBox) $buildPageGrid = [Grid]::new() $buildPageGrid.RowSpacing = 10 $buildPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildPageGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::new(1, 'Star'))) $buildTitle = [TextBlock]::new() $buildTitle.FontSize = 18 $buildTitle.FontWeight = 'SemiBold' $buildTitle.Text = 'Build' $buildHintText = [TextBlock]::new() $buildHintText.Text = 'Build bootable ISO outputs or export selected install image indexes into a new WIM.' $buildHintText.TextWrapping = 'Wrap' [Grid]::SetRow($buildHintText, 1) $buildFormGrid = [Grid]::new() $buildFormGrid.ColumnSpacing = 8 $buildFormGrid.RowSpacing = 6 $buildFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildFormGrid.RowDefinitions.Add([RowDefinition]::new([GridLength]::Auto)) $buildFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2.2, 'Star'))) $buildFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2.2, 'Star'))) $buildFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(1.2, 'Star'))) $buildFormGrid.ColumnDefinitions.Add([ColumnDefinition]::new([GridLength]::new(2.2, 'Star'))) [Grid]::SetRow($buildFormGrid, 2) $buildMediaRootLabel = [TextBlock]::new(); $buildMediaRootLabel.Text = 'Media root'; [Grid]::SetColumn($buildMediaRootLabel, 0); [Grid]::SetRow($buildMediaRootLabel, 0) $buildOutputIsoLabel = [TextBlock]::new(); $buildOutputIsoLabel.Text = 'Output ISO'; [Grid]::SetColumn($buildOutputIsoLabel, 1); [Grid]::SetRow($buildOutputIsoLabel, 0) $buildLabelLabel = [TextBlock]::new(); $buildLabelLabel.Text = 'ISO label'; [Grid]::SetColumn($buildLabelLabel, 2); [Grid]::SetRow($buildLabelLabel, 0) $buildSourceImageLabel = [TextBlock]::new(); $buildSourceImageLabel.Text = 'Source image (install.wim/esd)'; [Grid]::SetColumn($buildSourceImageLabel, 3); [Grid]::SetRow($buildSourceImageLabel, 0) $buildMediaRootTextBox = [TextBox]::new(); $buildMediaRootTextBox.Watermark = 'C:\work\splitter\Standard'; [Grid]::SetColumn($buildMediaRootTextBox, 0); [Grid]::SetRow($buildMediaRootTextBox, 1) $buildOutputIsoTextBox = [TextBox]::new(); $buildOutputIsoTextBox.Watermark = 'C:\out\Standard.iso'; [Grid]::SetColumn($buildOutputIsoTextBox, 1); [Grid]::SetRow($buildOutputIsoTextBox, 1) $buildLabelTextBox = [TextBox]::new(); $buildLabelTextBox.Watermark = 'WINSTD'; [Grid]::SetColumn($buildLabelTextBox, 2); [Grid]::SetRow($buildLabelTextBox, 1) $buildSourceImageTextBox = [TextBox]::new(); $buildSourceImageTextBox.Watermark = 'C:\work\splitter\sources\install.wim'; [Grid]::SetColumn($buildSourceImageTextBox, 3); [Grid]::SetRow($buildSourceImageTextBox, 1) $buildDestinationWimLabel = [TextBlock]::new(); $buildDestinationWimLabel.Text = 'Destination WIM'; [Grid]::SetColumn($buildDestinationWimLabel, 0); [Grid]::SetRow($buildDestinationWimLabel, 2) $buildIndexesLabel = [TextBlock]::new(); $buildIndexesLabel.Text = 'Indexes'; [Grid]::SetColumn($buildIndexesLabel, 1); [Grid]::SetRow($buildIndexesLabel, 2) $buildDestinationWimTextBox = [TextBox]::new(); $buildDestinationWimTextBox.Watermark = 'C:\out\install-custom.wim'; [Grid]::SetColumn($buildDestinationWimTextBox, 0); [Grid]::SetRow($buildDestinationWimTextBox, 3) $buildIndexesTextBox = [TextBox]::new(); $buildIndexesTextBox.Watermark = '1,2'; [Grid]::SetColumn($buildIndexesTextBox, 1); [Grid]::SetRow($buildIndexesTextBox, 3) $buildActionsStack = [StackPanel]::new() $buildActionsStack.Orientation = 'Horizontal' $buildActionsStack.Spacing = 8 [Grid]::SetColumn($buildActionsStack, 3) [Grid]::SetRow($buildActionsStack, 3) $buildBootableIsoButton = [Button]::new(); $buildBootableIsoButton.Height = 32; $buildBootableIsoButton.Content = 'Build Bootable ISO' $exportInstallImageButton = [Button]::new(); $exportInstallImageButton.Height = 32; $exportInstallImageButton.Content = 'Export Install Image' $buildBootableIsoButton.Background = $accentColor; $buildBootableIsoButton.Foreground = $textOnAccentColor $exportInstallImageButton.Background = $accentColor; $exportInstallImageButton.Foreground = $textOnAccentColor $buildActionsStack.Children.Add($buildBootableIsoButton) $buildActionsStack.Children.Add($exportInstallImageButton) $buildFormGrid.Children.Add($buildMediaRootLabel) $buildFormGrid.Children.Add($buildOutputIsoLabel) $buildFormGrid.Children.Add($buildLabelLabel) $buildFormGrid.Children.Add($buildSourceImageLabel) $buildFormGrid.Children.Add($buildMediaRootTextBox) $buildFormGrid.Children.Add($buildOutputIsoTextBox) $buildFormGrid.Children.Add($buildLabelTextBox) $buildFormGrid.Children.Add($buildSourceImageTextBox) $buildFormGrid.Children.Add($buildDestinationWimLabel) $buildFormGrid.Children.Add($buildIndexesLabel) $buildFormGrid.Children.Add($buildDestinationWimTextBox) $buildFormGrid.Children.Add($buildIndexesTextBox) $buildFormGrid.Children.Add($buildActionsStack) $buildLogHeader = [TextBlock]::new() $buildLogHeader.FontWeight = 'SemiBold' $buildLogHeader.Text = 'Build activity' $buildLogHeader.Foreground = $accentColor [Grid]::SetRow($buildLogHeader, 3) $buildLogTextBox = [TextBox]::new() $buildLogTextBox.AcceptsReturn = $true $buildLogTextBox.IsReadOnly = $true $buildLogTextBox.TextWrapping = 'NoWrap' $buildLogTextBox.IsUndoEnabled = $false $buildLogTextBox.FontFamily = 'Cascadia Mono' $buildLogTextBox.Padding = [Thickness]::new(8, 6, 8, 30) [Grid]::SetRow($buildLogTextBox, 4) $buildPageGrid.Children.Add($buildTitle) $buildPageGrid.Children.Add($buildHintText) $buildPageGrid.Children.Add($buildFormGrid) $buildPageGrid.Children.Add($buildLogHeader) $buildPageGrid.Children.Add($buildLogTextBox) $pageMap = @{ 'Split Editions' = $splitPageGrid 'Source Media' = $mediaPageGrid 'Image Servicing' = $servicingPageGrid 'Build Outputs' = $buildPageGrid } $setActivePage = { param( [Parameter(Mandatory)] [string] $PageKey ) $pageHostGrid.Children.Clear() $pageHostGrid.Children.Add($pageMap[$PageKey]) }.GetNewClosure() $navListBox.AddSelectionChanged({ if ($null -eq $navListBox.SelectedItem) { return } $selectedPage = $null if ($navListBox.SelectedItem -is [ListBoxItem]) { $selectedPage = [string] $navListBox.SelectedItem.Content } else { $selectedPage = [string] $navListBox.SelectedItem } if ($pageMap.ContainsKey($selectedPage)) { $setActivePage.Invoke($selectedPage) } }.GetNewClosure()) $navListBox.SelectedIndex = 0 $setActivePage.Invoke('Source Media') $shellGrid.Children.Add($navGrid) $shellGrid.Children.Add($pageHostGrid) $footerText = [TextBlock]::new() $footerText.Text = 'Preflight checks help avoid ADK, DISM, and path issues before long-running operations.' [Grid]::SetRow($footerText, 3) $rootGrid.Children.Add($headerGrid) $rootGrid.Children.Add($statusText) $rootGrid.Children.Add($shellGrid) $rootGrid.Children.Add($footerText) $win.Content = $rootGrid $controls = @{ StatusText = $statusText FooterText = $footerText SourceIsoTextBox = $sourceIsoTextBox BrowseSourceIsoButton = $browseSourceIsoButton EditionNamesTextBox = $editionNamesTextBox WorkingRootTextBox = $workingRootTextBox OutputRootTextBox = $outputRootTextBox OutputBaseNameTextBox = $outputBaseNameTextBox LabelPrefixTextBox = $labelPrefixTextBox SkipBootableIsoCheckBox = $skipBootableIsoCheckBox DesktopExperienceCheckBox = $desktopExperienceCheckBox ServerCoreCheckBox = $serverCoreCheckBox DiscoverImagesButton = $discoverImagesButton RunSplitButton = $runSplitButton RunPreflightButton = $runPreflightButton ImagesListBox = $imagesListBox MediaLogTextBox = $mediaLogTextBox ServiceMediaRootTextBox = $serviceMediaRootTextBox DriverPathTextBox = $driverPathTextBox PackagePathTextBox = $packagePathTextBox ServiceIndexesTextBox = $serviceIndexesTextBox UnattendPathTextBox = $unattendPathTextBox UnattendDestinationTextBox = $unattendDestinationTextBox ServiceRecurseDriversCheckBox = $serviceRecurseDriversCheckBox ServiceForceUnsignedDriversCheckBox = $serviceForceUnsignedDriversCheckBox ServiceIgnoreCheckCheckBox = $serviceIgnoreCheckCheckBox ServicePreventPendingCheckBox = $servicePreventPendingCheckBox AddDriverButton = $addDriverButton AddPackageButton = $addPackageButton AddUnattendButton = $addUnattendButton AddPayloadFileButton = $addPayloadFileButton PayloadSourceTextBox = $payloadSourceTextBox PayloadDestinationTextBox = $payloadDestinationTextBox ServicingLogTextBox = $servicingLogTextBox ServicingSelectionsListBox = $servicingSelectionsListBox BuildMediaRootTextBox = $buildMediaRootTextBox BuildOutputIsoTextBox = $buildOutputIsoTextBox BuildLabelTextBox = $buildLabelTextBox BuildSourceImageTextBox = $buildSourceImageTextBox BuildDestinationWimTextBox = $buildDestinationWimTextBox BuildIndexesTextBox = $buildIndexesTextBox BuildBootableIsoButton = $buildBootableIsoButton ExportInstallImageButton = $exportInstallImageButton BuildLogTextBox = $buildLogTextBox LogTextBox = $logTextBox ResultsListBox = $resultsListBox NavigationListBox = $navListBox PageHostGrid = $pageHostGrid } $tooltips = @{ NavigationListBox = 'Select the workflow stage you want to configure and run.' SourceIsoTextBox = 'Path to the source Windows ISO used for discovery and split operations.' BrowseSourceIsoButton = 'Browse for the source Windows ISO file.' EditionNamesTextBox = 'Comma-separated edition names to split, for example: Standard,Datacenter.' WorkingRootTextBox = 'Working folder where media is extracted and staged.' OutputRootTextBox = 'Destination folder for generated ISO and WIM outputs.' OutputBaseNameTextBox = 'Base filename prefix for generated media artifacts.' LabelPrefixTextBox = 'Volume label prefix used when creating bootable ISO files.' SkipBootableIsoCheckBox = 'Skip ISO creation during split and keep only staged file outputs.' DesktopExperienceCheckBox = 'Limit processing to Desktop Experience editions when available.' ServerCoreCheckBox = 'Limit processing to Server Core editions when available.' DiscoverImagesButton = 'Scan the source media and list install image indexes and names.' RunPreflightButton = 'Run ADK, DISM, and path checks before long-running operations.' RunSplitButton = 'Run split operations using current settings and selected editions.' ImagesListBox = 'Discovered install images from the selected source ISO.' MediaLogTextBox = 'Log output for media discovery and preflight operations.' LogTextBox = 'Log output for split execution and workflow status.' ResultsListBox = 'Latest operation results and produced artifacts.' ServiceMediaRootTextBox = 'Extracted media root folder to service with drivers, packages, and unattend.' DriverPathTextBox = 'Driver folder or INF path. Leave blank and click Add Driver to choose.' PackagePathTextBox = 'CAB or MSU path. Leave blank and click Add Package to choose.' ServiceIndexesTextBox = 'Comma-separated image indexes to service, for example: 1,2.' UnattendPathTextBox = 'Unattend XML path. Leave blank and click Add Unattend to choose.' UnattendDestinationTextBox = 'Destination filename or relative path for unattend XML in media root.' ServiceRecurseDriversCheckBox = 'Include subfolders when scanning for driver files.' ServiceForceUnsignedDriversCheckBox = 'Allow unsigned drivers when adding drivers to images.' ServiceIgnoreCheckCheckBox = 'Ignore package applicability checks during package add.' ServicePreventPendingCheckBox = 'Skip package actions when pending operations are detected.' AddDriverButton = 'Add drivers from the specified path to selected image indexes.' AddPackageButton = 'Add package updates from the specified CAB or MSU file.' AddUnattendButton = 'Copy unattend XML into the media root using the destination name.' AddPayloadFileButton = 'Copy a payload file like an MSI into media at a relative destination path.' PayloadSourceTextBox = 'Payload file path. Leave blank and click Add Payload File to choose.' PayloadDestinationTextBox = 'Relative destination under media root, for example sources\\$OEM$\\$1\\Install\\PowerShell-7.6.3-win-x64.msi.' ServicingLogTextBox = 'Log output for servicing operations.' ServicingSelectionsListBox = 'Shows selected and added servicing items for traceability.' BuildMediaRootTextBox = 'Media root folder used to build a bootable ISO.' BuildOutputIsoTextBox = 'Output path for the bootable ISO to create.' BuildLabelTextBox = 'Volume label to stamp into the generated ISO.' BuildSourceImageTextBox = 'Source install.wim or install.esd used for export operations.' BuildDestinationWimTextBox = 'Destination path for exported custom install WIM.' BuildIndexesTextBox = 'Comma-separated image indexes to export, for example: 1,2.' BuildBootableIsoButton = 'Build a bootable ISO from the media root and output settings.' ExportInstallImageButton = 'Export selected image indexes into a destination WIM.' BuildLogTextBox = 'Log output for build and export operations.' StatusText = 'Current preflight and workflow status summary.' FooterText = 'General guidance for running preflight before long operations.' } foreach ($controlName in $tooltips.Keys) { if ($controls.ContainsKey($controlName) -and $null -ne $controls[$controlName]) { [GliderUI.Avalonia.Controls.ToolTip]::SetTip($controls[$controlName], $tooltips[$controlName]) } } [pscustomobject]@{ Window = $win Controls = $controls } } |