function Set-DeployCenterButtonStyle { param( [Parameter(Mandatory=$true)][System.Windows.Forms.Button]$Button, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [ValidateSet('Button','PrimaryButton','DangerButton')][string]$Role = 'Button' ) $style = $Theme[$Role] $Button.BackColor = $style.Background $Button.ForeColor = $style.Foreground $Button.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $Button.UseVisualStyleBackColor = $false $Button.FlatAppearance.BorderSize = 1 $Button.FlatAppearance.BorderColor = $style.Border $Button.FlatAppearance.MouseOverBackColor = $style.HoverBackground $Button.FlatAppearance.MouseDownBackColor = $style.PressedBackground if (-not $Button.Enabled) { $Button.BackColor = $style.DisabledBackground $Button.ForeColor = $style.DisabledForeground } } function New-DeployCenterComboBox { param( [Parameter(Mandatory=$true)][string]$Name, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font, [Parameter(Mandatory=$true)][AllowEmptyCollection()][string[]]$Items ) $comboBox = New-Object System.Windows.Forms.ComboBox $comboBox.Name = $Name $comboBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList $comboBox.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $comboBox.BackColor = $Theme.PanelAlt $comboBox.ForeColor = $Theme.Text $comboBox.Font = $Font $comboBox.IntegralHeight = $false $comboBox.MaxDropDownItems = 12 foreach ($item in $Items) { [void]$comboBox.Items.Add($item) } return $comboBox } function Set-DeployCenterComboBoxTheme { param( [Parameter(Mandatory=$true)][System.Windows.Forms.ComboBox]$ComboBox, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme ) $ComboBox.BackColor = $Theme.PanelAlt $ComboBox.ForeColor = $Theme.Text } function New-DeployCenterPartitionProfileSelector { param( [Parameter(Mandatory=$true)][System.Windows.Forms.GroupBox]$Parent, [Parameter(Mandatory=$true)][string[]]$ProfileNames, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font ) $label = New-Object System.Windows.Forms.Label $label.Text = 'Profil de partitionnement' $label.Size = New-Object System.Drawing.Size(240, 17) $label.ForeColor = $Theme.Text $label.BackColor = [System.Drawing.Color]::Transparent $label.Font = $Font $comboBox = New-DeployCenterComboBox -Name 'cmbPartitionProfile' -Theme $Theme -Font $Font -Items $ProfileNames $Parent.Controls.Add($label) $Parent.Controls.Add($comboBox) Set-DeployCenterPartitionProfileSelectorLayout -Label $label -ComboBox $comboBox -Width ($Parent.ClientSize.Width - 24) return [pscustomobject]@{ Label = $label; ComboBox = $comboBox } } function Set-DeployCenterPartitionProfileSelectorLayout { param( [Parameter(Mandatory=$true)][System.Windows.Forms.Label]$Label, [Parameter(Mandatory=$true)][System.Windows.Forms.ComboBox]$ComboBox, [Parameter(Mandatory=$true)][int]$Width ) $Label.Location = New-Object System.Drawing.Point(12, 139) $ComboBox.Location = New-Object System.Drawing.Point(12, 157) $ComboBox.Size = New-Object System.Drawing.Size([Math]::Max(250, $Width), 26) } function New-DeployCenterDeploymentControls { param( [Parameter(Mandatory=$true)][System.Windows.Forms.GroupBox]$Parent, [Parameter(Mandatory=$true)][string[]]$ProfileNames, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font ) $diskLabel = New-Object System.Windows.Forms.Label $diskLabel.Text = 'Disque physique' $diskLabel.Location = New-Object System.Drawing.Point(12, 20) $diskLabel.Size = New-Object System.Drawing.Size(220, 18) $diskLabel.Font = $Font $diskLabel.ForeColor = $Theme.Text $diskLabel.BackColor = [System.Drawing.Color]::Transparent $diskCombo = New-DeployCenterComboBox -Name 'cmbDisk' -Theme $Theme -Font $Font -Items @() $diskCombo.Location = New-Object System.Drawing.Point(12, 39) $diskCombo.Size = New-Object System.Drawing.Size([Math]::Max(250, $Parent.ClientSize.Width - 24), 26) $diskCombo.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right $systemLabel = New-Object System.Windows.Forms.Label $systemLabel.Text = 'Système à installer' $systemLabel.Location = New-Object System.Drawing.Point(12, 71) $systemLabel.Size = New-Object System.Drawing.Size(240, 18) $systemLabel.Font = $Font $systemLabel.ForeColor = $Theme.Text $systemLabel.BackColor = [System.Drawing.Color]::Transparent $chooseSystemButton = New-Object System.Windows.Forms.Button $chooseSystemButton.Name = 'btnChooseWindows' $chooseSystemButton.Text = 'Choisir…' $chooseSystemButton.Size = New-Object System.Drawing.Size(132, 28) $chooseSystemButton.Location = New-Object System.Drawing.Point([Math]::Max(12, $Parent.ClientSize.Width - 144), 67) $chooseSystemButton.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Right Set-DeployCenterButtonStyle -Button $chooseSystemButton -Theme $Theme -Role 'Button' $selectedSystemLabel = New-Object System.Windows.Forms.Label $selectedSystemLabel.Name = 'lblSelectedWindows' $selectedSystemLabel.Text = 'Aucun système sélectionné' $selectedSystemLabel.Location = New-Object System.Drawing.Point(12, 98) $selectedSystemLabel.Size = New-Object System.Drawing.Size([Math]::Max(250, $Parent.ClientSize.Width - 24), 22) $selectedSystemLabel.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right $selectedSystemLabel.Font = $Font $selectedSystemLabel.AutoEllipsis = $true $selectedSystemLabel.ForeColor = $Theme.Secondary $selectedSystemLabel.BackColor = [System.Drawing.Color]::Transparent $profileSelector = New-DeployCenterPartitionProfileSelector -Parent $Parent -ProfileNames $ProfileNames -Theme $Theme -Font $Font $profileSelector.ComboBox.Enabled = $false $unattendLabel = New-Object System.Windows.Forms.Label $unattendLabel.Name = 'lblUnattendProfile' $unattendLabel.Text = 'Configuration de première ouverture' $unattendLabel.Location = New-Object System.Drawing.Point(12, 190) $unattendLabel.Size = New-Object System.Drawing.Size(320, 17) $unattendLabel.Font = $Font $unattendLabel.ForeColor = $Theme.Text $unattendLabel.BackColor = [System.Drawing.Color]::Transparent $unattendCombo = New-DeployCenterComboBox -Name 'cmbUnattendProfile' -Theme $Theme -Font $Font ` -Items @('Avec OOBE') $unattendCombo.Location = New-Object System.Drawing.Point(12, 207) $unattendCombo.Size = New-Object System.Drawing.Size([Math]::Max(250, $Parent.ClientSize.Width - 24), 26) $unattendCombo.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right $unattendCombo.SelectedIndex = 0 $hostLabel = New-Object System.Windows.Forms.Label $hostLabel.Name = 'lblHostName' $hostLabel.Text = "Nom d’hôte" $hostLabel.Location = New-Object System.Drawing.Point(12, 240) $hostLabel.Size = New-Object System.Drawing.Size(220, 24) $hostLabel.Font = $Font $hostLabel.ForeColor = $Theme.Text $hostLabel.BackColor = [System.Drawing.Color]::Transparent $hostTextBox = New-Object System.Windows.Forms.TextBox $hostTextBox.Name = 'txtHostName' $hostTextBox.Location = New-Object System.Drawing.Point([Math]::Max(244, $Parent.ClientSize.Width - 202), 237) $hostTextBox.Size = New-Object System.Drawing.Size(190, 26) $hostTextBox.MaxLength = 15 $hostTextBox.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Right $hostTextBox.BackColor = $Theme.PanelAlt $hostTextBox.ForeColor = $Theme.Text $hostTextBox.Font = $Font $hostLabel.Visible = $false $hostTextBox.Visible = $false $Parent.Controls.AddRange(@($diskLabel, $diskCombo, $systemLabel, $chooseSystemButton, $selectedSystemLabel, $unattendLabel, $unattendCombo, $hostLabel, $hostTextBox)) return [pscustomobject]@{ DiskComboBox = $diskCombo ChooseSystemButton = $chooseSystemButton SelectedSystemLabel = $selectedSystemLabel PartitionProfileLabel = $profileSelector.Label PartitionProfileComboBox = $profileSelector.ComboBox UnattendProfileLabel = $unattendLabel UnattendProfileComboBox = $unattendCombo HostNameLabel = $hostLabel HostNameTextBox = $hostTextBox } } function Set-DeployCenterUnattendHostNameVisibility { param([Parameter(Mandatory=$true)]$Controls, [Parameter(Mandatory=$true)][bool]$ShowHostName) $Controls.HostNameLabel.Visible = $ShowHostName $Controls.HostNameTextBox.Visible = $ShowHostName } function Set-DeployCenterUnattendProfileChoices { param( [Parameter(Mandatory=$true)][System.Windows.Forms.ComboBox]$ComboBox, [Parameter(Mandatory=$true)][AllowEmptyCollection()][object[]]$Profiles, [AllowNull()][string]$EditionName, [Parameter(Mandatory=$true)][string]$OobeChoice ) $isServerEdition = -not [string]::IsNullOrWhiteSpace($EditionName) -and $EditionName.IndexOf('server', [StringComparison]::OrdinalIgnoreCase) -ge 0 $target = if ($isServerEdition) { 'Server' } else { 'Workstation' } $choices = @($OobeChoice) if (-not [string]::IsNullOrWhiteSpace($EditionName)) { $choices += @($Profiles | Where-Object { [string]$_.Target -eq $target } | ForEach-Object { [string]$_.Name }) } $previousChoice = [string]$ComboBox.SelectedItem $ComboBox.BeginUpdate() try { $ComboBox.Items.Clear() foreach ($choice in $choices) { [void]$ComboBox.Items.Add($choice) } $selectionIndex = $ComboBox.Items.IndexOf($previousChoice) if ($selectionIndex -lt 0) { $selectionIndex = 0 } $ComboBox.SelectedIndex = $selectionIndex } finally { $ComboBox.EndUpdate() } } function Set-DeployCenterDeploymentControlsLayout { param( [Parameter(Mandatory=$true)][System.Windows.Forms.GroupBox]$Parent, [Parameter(Mandatory=$true)]$Controls ) $width = [Math]::Max(250, $Parent.ClientSize.Width - 24) $Controls.DiskComboBox.Size = New-Object System.Drawing.Size($width, 26) $Controls.ChooseSystemButton.Location = New-Object System.Drawing.Point([Math]::Max(12, $Parent.ClientSize.Width - 144), 67) $Controls.SelectedSystemLabel.Size = New-Object System.Drawing.Size($width, 22) Set-DeployCenterPartitionProfileSelectorLayout -Label $Controls.PartitionProfileLabel -ComboBox $Controls.PartitionProfileComboBox -Width $width $Controls.UnattendProfileComboBox.Size = New-Object System.Drawing.Size($width, 26) $Controls.HostNameTextBox.Location = New-Object System.Drawing.Point([Math]::Max(244, $Parent.ClientSize.Width - 202), 237) $Controls.HostNameTextBox.Size = New-Object System.Drawing.Size(190, 26) } function New-DeployCenterLogWindow { param( [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font ) $form = New-Object System.Windows.Forms.Form $form.Text = 'Journal DeployCenter' $form.StartPosition = 'CenterParent' $form.Size = New-Object System.Drawing.Size(900, 500) $form.MinimumSize = New-Object System.Drawing.Size(560, 300) $form.ShowInTaskbar = $false $form.BackColor = $Theme.Background $form.ForeColor = $Theme.Text $form.Font = $Font $textBox = New-Object System.Windows.Forms.TextBox $textBox.Name = 'txtLog' $textBox.Location = New-Object System.Drawing.Point(12, 12) $textBox.Size = New-Object System.Drawing.Size(860, 440) $textBox.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right $textBox.Multiline = $true $textBox.ReadOnly = $true $textBox.WordWrap = $false $textBox.ScrollBars = [System.Windows.Forms.ScrollBars]::Both $textBox.BackColor = $Theme.PanelAlt $textBox.ForeColor = $Theme.Text $textBox.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle $textBox.Font = [System.Drawing.Font]::new('Consolas', [single]9, [System.Drawing.FontStyle]::Regular) $form.Controls.Add($textBox) $form.Add_FormClosing({ if ($_.CloseReason -eq [System.Windows.Forms.CloseReason]::UserClosing) { $_.Cancel = $true; $form.Hide() } }.GetNewClosure()) return [pscustomobject]@{ Form = $form; TextBox = $textBox } } function Show-DeployCenterPartitionSizingDialog { param( [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Profile, [Parameter(Mandatory=$true)][double]$AvailableGB, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font, [System.Windows.Forms.Form]$Owner = $null, [System.Collections.IDictionary]$InitialValues = @{} ) $inputs = @($Profile.Partitions | Where-Object { [string]$_.Size.Policy -eq 'UserInputGB' }) $remainder = @($Profile.Partitions | Where-Object { [string]$_.Size.Policy -eq 'RemainderAfterInputs' })[0] if ($inputs.Count -eq 0 -or $null -eq $remainder) { return $null } $minimumRemainder = [double]$remainder.Size.MinimumGB $minimumInputs = 0.0 foreach ($inputDefinition in $inputs) { $minimumInputs += [double]$inputDefinition.Size.MinimumGB } if ($AvailableGB -lt ($minimumInputs + $minimumRemainder)) { Show-DeployCenterMessage ` -Message "L'espace disponible sur ce disque est insuffisant pour le profil '$($Profile.Name)'." ` -Title 'Partitionnement impossible' -Icon Warning -Owner $Owner -Theme $Theme -Font $Font return $null } $dialog = New-Object System.Windows.Forms.Form $dialog.Text = 'Tailles des partitions' $dialog.StartPosition = if ($Owner) { 'CenterParent' } else { 'CenterScreen' } $dialog.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog $dialog.ShowInTaskbar = $false $dialog.MinimizeBox = $false $dialog.MaximizeBox = $false $dialog.BackColor = $Theme.Background $dialog.ForeColor = $Theme.Text $dialog.Font = $Font $dialog.ClientSize = New-Object System.Drawing.Size(470, (152 + ($inputs.Count * 42))) $capacityLabel = New-Object System.Windows.Forms.Label $capacityLabel.Location = New-Object System.Drawing.Point(18, 16) $capacityLabel.Size = New-Object System.Drawing.Size(430, 34) $recoveryPartition = @($Profile.Partitions | Where-Object { [string]$_.Role -eq 'Recovery' }) | Select-Object -First 1 $winreSizeMB = if ($recoveryPartition) { [int]$recoveryPartition.Size.Value } else { 1024 } $capacityLabel.Text = "Capacité estimée après réservation EFI, MSR et WinRE : {0:N1} Go.`r`nTaille WinRE configurée : {1} Mo." -f $AvailableGB, $winreSizeMB $capacityLabel.ForeColor = $Theme.Text $capacityLabel.BackColor = [System.Drawing.Color]::Transparent $capacityLabel.Font = $Font $dialog.Controls.Add($capacityLabel) $inputControls = [System.Collections.Generic.List[object]]::new() for ($i = 0; $i -lt $inputs.Count; $i++) { $definition = $inputs[$i] $rowY = 60 + ($i * 42) $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(18, ($rowY + 4)) $label.Size = New-Object System.Drawing.Size(250, 26) $label.Text = [string]$definition.Size.Label $label.ForeColor = $Theme.Text $label.BackColor = [System.Drawing.Color]::Transparent $label.Font = $Font $dialog.Controls.Add($label) $otherMinimums = 0.0 for ($j = 0; $j -lt $inputs.Count; $j++) { if ($j -ne $i) { $otherMinimums += [double]$inputs[$j].Size.MinimumGB } } $maximum = [math]::Floor($AvailableGB - $minimumRemainder - $otherMinimums) $minimum = [double]$definition.Size.MinimumGB $numeric = New-Object System.Windows.Forms.NumericUpDown $numeric.Location = New-Object System.Drawing.Point(292, $rowY) $numeric.Size = New-Object System.Drawing.Size(150, 28) $numeric.Minimum = [decimal]$minimum $numeric.Maximum = [decimal]$maximum $numeric.DecimalPlaces = 0 $numeric.Increment = 1 $numeric.BackColor = $Theme.PanelAlt $numeric.ForeColor = $Theme.Text $numeric.Font = $Font $initialValue = $null if ($InitialValues.Contains([string]$definition.Role)) { $initialValue = [double]$InitialValues[[string]$definition.Role] } if ($null -eq $initialValue) { $initialValue = [math]::Floor($AvailableGB * ([double]$definition.Size.DefaultPercent / 100)) } $initialValue = [math]::Max($minimum, [math]::Min($maximum, $initialValue)) $numeric.Value = [decimal]$initialValue $inputControls.Add([pscustomobject]@{ Role = [string]$definition.Role; Control = $numeric }) $dialog.Controls.Add($numeric) } $remainderLabel = New-Object System.Windows.Forms.Label $remainderLabel.Location = New-Object System.Drawing.Point(18, (62 + ($inputs.Count * 42))) $remainderLabel.Size = New-Object System.Drawing.Size(430, 26) $remainderLabel.ForeColor = $Theme.Secondary $remainderLabel.BackColor = [System.Drawing.Color]::Transparent $remainderLabel.Font = $Font $dialog.Controls.Add($remainderLabel) $buttonPanel = New-Object System.Windows.Forms.Panel $buttonPanel.Dock = [System.Windows.Forms.DockStyle]::Bottom $buttonPanel.Height = 58 $buttonPanel.BackColor = $Theme.PanelAlt $dialog.Controls.Add($buttonPanel) $cancelButton = New-Object System.Windows.Forms.Button $cancelButton.Text = 'Annuler' $cancelButton.Location = New-Object System.Drawing.Point(258, 10) $cancelButton.Size = New-Object System.Drawing.Size(92, 36) $cancelButton.Font = $Font $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel Set-DeployCenterButtonStyle -Button $cancelButton -Theme $Theme -Role 'Button' $buttonPanel.Controls.Add($cancelButton) $validateButton = New-Object System.Windows.Forms.Button $validateButton.Text = 'Valider' $validateButton.Location = New-Object System.Drawing.Point(358, 10) $validateButton.Size = New-Object System.Drawing.Size(92, 36) $validateButton.Font = $Font Set-DeployCenterButtonStyle -Button $validateButton -Theme $Theme -Role 'PrimaryButton' $buttonPanel.Controls.Add($validateButton) $dialog.Tag = [pscustomobject]@{ InputControls = $inputControls; AvailableGB = $AvailableGB } $updateRemainder = { $sum = 0.0 foreach ($inputControl in $dialog.Tag.InputControls) { $inputValue = [double]$inputControl.Control.Value $typedValue = 0.0 if ([double]::TryParse([string]$inputControl.Control.Text, [ref]$typedValue)) { $inputValue = $typedValue } $sum += $inputValue } $remainingGB = $dialog.Tag.AvailableGB - $sum $remainderDrive = [string]$remainder.DriveLetter $remainderName = if ($remainderDrive) { "$remainderDrive`:" } else { [string]$remainder.Name } $remainderLabel.Text = "{0} : {1:N1} Go (espace restant)" -f $remainderName, $remainingGB $remainderLabel.ForeColor = if ($remainingGB -lt $minimumRemainder) { $Theme.Danger } else { $Theme.Secondary } $validateButton.Enabled = ($remainingGB -ge $minimumRemainder) }.GetNewClosure() foreach ($inputControl in $inputControls) { $inputControl.Control.Add_ValueChanged($updateRemainder) $inputControl.Control.Add_TextChanged($updateRemainder) } & $updateRemainder $validateButton.Add_Click({ $inputValues = @{} foreach ($inputControl in $dialog.Tag.InputControls) { $inputValues[$inputControl.Role] = [double]$inputControl.Control.Value } $sum = 0.0 foreach ($value in $inputValues.Values) { $sum += [double]$value } $dialog.Tag = [pscustomobject]@{ Inputs = $inputValues RemainderRole = [string]$remainder.Role RemainderGB = [math]::Round(($dialog.Tag.AvailableGB - $sum), 1) AvailableGB = $dialog.Tag.AvailableGB } $dialog.DialogResult = [System.Windows.Forms.DialogResult]::OK $dialog.Close() }) $dialog.AcceptButton = $validateButton $dialog.CancelButton = $cancelButton if ($Owner) { $result = $dialog.ShowDialog($Owner) } else { $result = $dialog.ShowDialog() } $selection = if ($result -eq [System.Windows.Forms.DialogResult]::OK) { $dialog.Tag } else { $null } $dialog.Dispose() return $selection } function Show-DeployCenterMessage { param( [Parameter(Mandatory=$true)][string]$Message, [Parameter(Mandatory=$true)][string]$Title, [ValidateSet('Information','Warning','Error')][string]$Icon = 'Information', [System.Windows.Forms.Form]$Owner = $null, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font ) $messageForm = New-Object System.Windows.Forms.Form $messageForm.Text = $Title $messageForm.StartPosition = if ($Owner) { 'CenterParent' } else { 'CenterScreen' } $messageForm.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog $messageForm.ShowInTaskbar = $false $messageForm.MinimizeBox = $false $messageForm.MaximizeBox = $false $messageForm.BackColor = $Theme.Background $messageForm.ForeColor = $Theme.Text $messageForm.Font = $Font $messageWidth = 390 $textSize = [System.Windows.Forms.TextRenderer]::MeasureText( $Message, $Font, (New-Object System.Drawing.Size($messageWidth, 0)), [System.Windows.Forms.TextFormatFlags]::WordBreak ) $messageHeight = [Math]::Max(42, $textSize.Height + 8) $messageForm.ClientSize = New-Object System.Drawing.Size(470, ($messageHeight + 94)) $iconLabel = New-Object System.Windows.Forms.Label $iconLabel.Location = New-Object System.Drawing.Point(18, 24) $iconLabel.Size = New-Object System.Drawing.Size(34, 34) $iconLabel.Text = if ($Icon -eq 'Information') { 'i' } else { '!' } $iconLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter $iconLabel.Font = New-Object System.Drawing.Font('Segoe UI', [single]16, [System.Drawing.FontStyle]::Bold) $iconLabel.ForeColor = if ($Icon -eq 'Error') { $Theme.Danger } else { $Theme.Accent } $iconLabel.BackColor = [System.Drawing.Color]::Transparent $messageForm.Controls.Add($iconLabel) $messageLabel = New-Object System.Windows.Forms.Label $messageLabel.Location = New-Object System.Drawing.Point(64, 20) $messageLabel.Size = New-Object System.Drawing.Size($messageWidth, $messageHeight) $messageLabel.Text = $Message $messageLabel.ForeColor = $Theme.Text $messageLabel.BackColor = [System.Drawing.Color]::Transparent $messageLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft $messageLabel.Font = $Font $messageForm.Controls.Add($messageLabel) $buttonPanel = New-Object System.Windows.Forms.Panel $buttonPanel.Dock = [System.Windows.Forms.DockStyle]::Bottom $buttonPanel.Height = 58 $buttonPanel.BackColor = $Theme.PanelAlt $messageForm.Controls.Add($buttonPanel) $okButton = New-Object System.Windows.Forms.Button $okButton.Text = 'OK' $okButton.Location = New-Object System.Drawing.Point(362, 10) $okButton.Size = New-Object System.Drawing.Size(92, 36) $okButton.Font = $Font $okButton.Cursor = [System.Windows.Forms.Cursors]::Hand $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK Set-DeployCenterButtonStyle -Button $okButton -Theme $Theme -Role 'PrimaryButton' $buttonPanel.Controls.Add($okButton) $messageForm.AcceptButton = $okButton $messageForm.CancelButton = $okButton if ($Owner) { [void]$messageForm.ShowDialog($Owner) } else { [void]$messageForm.ShowDialog() } $messageForm.Dispose() } function Show-DeployCenterDeploymentComplete { param( [Parameter(Mandatory=$true)][string]$Message, [Parameter(Mandatory=$true)][System.Windows.Forms.Form]$Owner, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font, [bool]$RestartByDefault = $true ) $dialog = New-Object System.Windows.Forms.Form $dialog.Text = 'Déploiement terminé' $dialog.StartPosition = 'CenterParent' $dialog.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog $dialog.ShowInTaskbar = $false $dialog.MinimizeBox = $false $dialog.MaximizeBox = $false $dialog.BackColor = $Theme.Background $dialog.ForeColor = $Theme.Text $dialog.Font = $Font $messageWidth = 390 $textSize = [System.Windows.Forms.TextRenderer]::MeasureText( $Message, $Font, (New-Object System.Drawing.Size($messageWidth, 0)), [System.Windows.Forms.TextFormatFlags]::WordBreak ) $messageHeight = [Math]::Max(42, $textSize.Height + 8) $dialog.ClientSize = New-Object System.Drawing.Size(470, ($messageHeight + 126)) $iconLabel = New-Object System.Windows.Forms.Label $iconLabel.Location = New-Object System.Drawing.Point(18, 24) $iconLabel.Size = New-Object System.Drawing.Size(34, 34) $iconLabel.Text = 'i' $iconLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter $iconLabel.Font = New-Object System.Drawing.Font('Segoe UI', [single]16, [System.Drawing.FontStyle]::Bold) $iconLabel.ForeColor = $Theme.Accent $iconLabel.BackColor = [System.Drawing.Color]::Transparent $dialog.Controls.Add($iconLabel) $messageLabel = New-Object System.Windows.Forms.Label $messageLabel.Location = New-Object System.Drawing.Point(64, 20) $messageLabel.Size = New-Object System.Drawing.Size($messageWidth, $messageHeight) $messageLabel.Text = $Message $messageLabel.ForeColor = $Theme.Text $messageLabel.BackColor = [System.Drawing.Color]::Transparent $messageLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft $messageLabel.Font = $Font $dialog.Controls.Add($messageLabel) $restartCheckBox = New-Object System.Windows.Forms.CheckBox $restartCheckBox.Text = 'Redémarrer cet ordinateur après fermeture' $restartCheckBox.Location = New-Object System.Drawing.Point(64, ($messageHeight + 34)) $restartCheckBox.Size = New-Object System.Drawing.Size(380, 26) $restartCheckBox.Checked = $RestartByDefault $restartCheckBox.ForeColor = $Theme.Text $restartCheckBox.BackColor = [System.Drawing.Color]::Transparent $restartCheckBox.Font = $Font $dialog.Controls.Add($restartCheckBox) $buttonPanel = New-Object System.Windows.Forms.Panel $buttonPanel.Dock = [System.Windows.Forms.DockStyle]::Bottom $buttonPanel.Height = 58 $buttonPanel.BackColor = $Theme.PanelAlt $dialog.Controls.Add($buttonPanel) $okButton = New-Object System.Windows.Forms.Button $okButton.Text = 'OK' $okButton.Location = New-Object System.Drawing.Point(362, 10) $okButton.Size = New-Object System.Drawing.Size(92, 36) $okButton.Font = $Font $okButton.Cursor = [System.Windows.Forms.Cursors]::Hand $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK Set-DeployCenterButtonStyle -Button $okButton -Theme $Theme -Role 'PrimaryButton' $buttonPanel.Controls.Add($okButton) $dialog.AcceptButton = $okButton $dialog.CancelButton = $okButton try { $result = $dialog.ShowDialog($Owner) return ($result -eq [System.Windows.Forms.DialogResult]::OK -and $restartCheckBox.Checked) } finally { $dialog.Dispose() } } function Show-DeployCenterConfirmation { param( [Parameter(Mandatory=$true)][string]$Title, [Parameter(Mandatory=$true)][string]$Message, [Parameter(Mandatory=$true)][System.Windows.Forms.Form]$Owner, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font ) $dialog = New-Object System.Windows.Forms.Form $dialog.Text = $Title $dialog.StartPosition = 'CenterParent' $dialog.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog $dialog.ShowInTaskbar = $false $dialog.MinimizeBox = $false $dialog.MaximizeBox = $false $dialog.ClientSize = New-Object System.Drawing.Size(540, 210) $dialog.BackColor = $Theme.Background $dialog.ForeColor = $Theme.Text $dialog.Font = $Font $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(18, 18) $label.Size = New-Object System.Drawing.Size(504, 120) $label.Text = $Message $label.ForeColor = $Theme.Text $label.BackColor = [System.Drawing.Color]::Transparent $label.Font = $Font $dialog.Controls.Add($label) $cancel = New-Object System.Windows.Forms.Button $cancel.Text = 'Annuler' $cancel.Location = New-Object System.Drawing.Point(310, 158) $cancel.Size = New-Object System.Drawing.Size(100, 36) $cancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel Set-DeployCenterButtonStyle -Button $cancel -Theme $Theme -Role 'Button' $dialog.Controls.Add($cancel) $confirm = New-Object System.Windows.Forms.Button $confirm.Text = 'Effacer et installer' $confirm.Location = New-Object System.Drawing.Point(420, 158) $confirm.Size = New-Object System.Drawing.Size(102, 36) $confirm.DialogResult = [System.Windows.Forms.DialogResult]::Yes Set-DeployCenterButtonStyle -Button $confirm -Theme $Theme -Role 'DangerButton' $dialog.Controls.Add($confirm) $dialog.CancelButton = $cancel $dialog.AcceptButton = $confirm return ($dialog.ShowDialog($Owner) -eq [System.Windows.Forms.DialogResult]::Yes) } function New-DeployCenterDeploymentProgress { param( [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font ) $form = New-Object System.Windows.Forms.Form $form.Text = 'Déploiement Windows' $form.StartPosition = 'CenterParent' $form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog $form.ControlBox = $false $form.ShowInTaskbar = $false $form.ClientSize = New-Object System.Drawing.Size(520, 116) $form.BackColor = $Theme.Background $form.ForeColor = $Theme.Text $form.Font = $Font $status = New-Object System.Windows.Forms.Label $status.Location = New-Object System.Drawing.Point(16, 16) $status.Size = New-Object System.Drawing.Size(488, 28) $status.Text = 'Préparation du déploiement…' $status.AutoEllipsis = $true $status.ForeColor = $Theme.Text $status.BackColor = [System.Drawing.Color]::Transparent $status.Font = $Font $form.Controls.Add($status) $bar = New-Object System.Windows.Forms.ProgressBar $bar.Location = New-Object System.Drawing.Point(16, 56) $bar.Size = New-Object System.Drawing.Size(488, 24) $bar.Style = [System.Windows.Forms.ProgressBarStyle]::Marquee $bar.MarqueeAnimationSpeed = 25 $form.Controls.Add($bar) return [pscustomobject]@{ Form = $form; StatusLabel = $status; ProgressBar = $bar; Action = $null } } function Set-DeployCenterFormSizing { param( [Parameter(Mandatory=$true)][System.Windows.Forms.Form]$Form, [switch]$Resizable ) if ($Resizable) { $Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Sizable $Form.MaximizeBox = $true } else { $Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog $Form.MaximizeBox = $false } } function Add-SessionFooter { param( [Parameter(Mandatory=$true)][System.Windows.Forms.Form]$TargetForm, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font, [AllowNull()][string]$IPv4, [AllowNull()][string]$VncPassword, [bool]$ShowFooter = $true, [bool]$ShowPassword = $true ) if (-not $ShowFooter) { return } $footer = New-Object System.Windows.Forms.Label $footer.Name = 'DeployCenterSessionFooter' $footer.Text = if ($IPv4) { "IP de déploiement : $IPv4" } else { 'IP de déploiement indisponible' } if ($ShowPassword -and -not [string]::IsNullOrWhiteSpace($VncPassword)) { $footer.Text += " | Mot de passe VNC : $VncPassword" } $footer.Height = 26 $footer.Dock = [System.Windows.Forms.DockStyle]::Bottom $footer.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft $footer.Padding = New-Object System.Windows.Forms.Padding(12, 0, 0, 0) $footer.BackColor = $Theme.PanelAlt $footer.ForeColor = $Theme.Text $footer.Font = $Font $TargetForm.Controls.Add($footer) $footer.BringToFront() } function New-Label { param( [Parameter(Mandatory=$true)][string]$Text, [Parameter(Mandatory=$true)][int]$X, [Parameter(Mandatory=$true)][int]$Y, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font, [int]$Width = 180, [int]$Height = 24, [AllowNull()]$Color = $null ) $label = New-Object System.Windows.Forms.Label $label.Text = $Text $label.Location = New-Object System.Drawing.Point($X, $Y) $label.Size = New-Object System.Drawing.Size($Width, $Height) $label.AutoEllipsis = $true $label.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft $label.BackColor = [System.Drawing.Color]::Transparent $label.ForeColor = if ($null -eq $Color) { $Theme.Text } else { $Color } $label.Font = $Font return $label } function New-GroupBox { param( [Parameter(Mandatory=$true)][string]$Text, [Parameter(Mandatory=$true)][int]$X, [Parameter(Mandatory=$true)][int]$Y, [Parameter(Mandatory=$true)][int]$Width, [Parameter(Mandatory=$true)][int]$Height, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font ) $group = New-Object DeployCenter.ThemedGroupBox $group.Text = $Text $group.Location = New-Object System.Drawing.Point($X, $Y) $group.Size = New-Object System.Drawing.Size($Width, $Height) $group.ForeColor = $Theme.Text $group.BackColor = $Theme.Panel $group.PanelColor = $Theme.Panel $group.BorderColor = $Theme.Border $group.TextColor = $Theme.Text $group.Font = $Font return $group } function New-Button { param( [Parameter(Mandatory=$true)][string]$Text, [Parameter(Mandatory=$true)][int]$X, [Parameter(Mandatory=$true)][int]$Y, [Parameter(Mandatory=$true)][int]$Width, [Parameter(Mandatory=$true)][int]$Height, [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Theme, [Parameter(Mandatory=$true)][System.Drawing.Font]$Font, [ValidateSet('Button','PrimaryButton','DangerButton')][string]$Role = 'Button' ) $button = New-Object System.Windows.Forms.Button $button.Text = $Text $button.Location = New-Object System.Drawing.Point($X, $Y) $button.Size = New-Object System.Drawing.Size($Width, $Height) $button.Tag = $Role Set-DeployCenterButtonStyle -Button $button -Theme $Theme -Role $Role $button.Font = $Font $button.Cursor = [System.Windows.Forms.Cursors]::Hand $button.AutoSize = $false $button.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter return $button } function Get-DeployCenterLogoPathForTheme { param( [Parameter(Mandatory=$true)][string]$ThemeName, [Parameter(Mandatory=$true)][string]$LogoPath, [Parameter(Mandatory=$true)][string]$LogoDarkPath ) if ($ThemeName -eq 'Dark' -and (Test-Path -LiteralPath $LogoDarkPath -PathType Leaf)) { return $LogoDarkPath } if (Test-Path -LiteralPath $LogoPath -PathType Leaf) { return $LogoPath } if (Test-Path -LiteralPath $LogoDarkPath -PathType Leaf) { return $LogoDarkPath } return $null } function Update-DeployCenterLogo { param( [Parameter(Mandatory=$true)][AllowNull()][System.Windows.Forms.PictureBox]$PictureBox, [Parameter(Mandatory=$true)][string]$ThemeName, [Parameter(Mandatory=$true)][string]$LogoPath, [Parameter(Mandatory=$true)][string]$LogoDarkPath ) if ($null -eq $PictureBox) { return } $selectedLogoPath = Get-DeployCenterLogoPathForTheme -ThemeName $ThemeName -LogoPath $LogoPath -LogoDarkPath $LogoDarkPath if ([string]::IsNullOrWhiteSpace($selectedLogoPath)) { return } try { $newImage = [System.Drawing.Image]::FromFile($selectedLogoPath) $oldImage = $PictureBox.Image $PictureBox.Image = $newImage if ($null -ne $oldImage) { $oldImage.Dispose() } $PictureBox.Visible = $true } catch { # Conserver le logo déjà affiché si le nouveau fichier est absent ou invalide. } } # Workflows de l'interface principale ; dot-sourcés pour partager explicitement l'état de session DeployCenter. function Set-DiskSelectorWidth { if ($null -eq $script:cmbDisk -or $null -eq $script:groupDisks) { return } Set-DeployCenterDeploymentControlsLayout -Parent $script:groupDisks -Controls $deploymentControls } function Set-ControlTheme { param([System.Windows.Forms.Control]$Control) # Le formulaire principal doit lui aussi changer de fond. if ($Control -is [System.Windows.Forms.Form]) { $Control.BackColor = $script:Theme.Background $Control.ForeColor = $script:Theme.Text } elseif ($Control -is [DeployCenter.ThemedGroupBox]) { $Control.BackColor = $script:Theme.Panel $Control.PanelColor = $script:Theme.Panel $Control.BorderColor = $script:Theme.Border $Control.TextColor = $script:Theme.Text $Control.ForeColor = $script:Theme.Text $Control.Invalidate() } elseif ($Control -is [System.Windows.Forms.Label]) { $Control.ForeColor = $script:Theme.Text if ($Control.Name -eq 'lblSelectedWindows') { $Control.ForeColor = if ($script:SelectedWindowsEdition) { $script:Theme.Success } else { $script:Theme.Secondary } } # Le pied de page VNC suit lui aussi la palette du thème actif. if ($Control.Name -eq 'DeployCenterSessionFooter') { $Control.BackColor = $script:Theme.PanelAlt $Control.ForeColor = $script:Theme.Secondary $Control.Invalidate() } } elseif ($Control -is [System.Windows.Forms.ListView]) { $Control.BackColor = $script:Theme.PanelAlt $Control.ForeColor = $script:Theme.Text } elseif ($Control -is [System.Windows.Forms.ComboBox]) { Set-DeployCenterComboBoxTheme -ComboBox $Control -Theme $script:Theme } elseif ($Control -is [System.Windows.Forms.TextBox]) { $Control.BackColor = $script:Theme.PanelAlt $Control.ForeColor = $script:Theme.Text } foreach ($child in $Control.Controls) { Set-ControlTheme -Control $child } } function Set-DeployCenterTheme { param([Parameter(Mandatory=$true)][string]$ThemeName) $availableThemes = @(Get-DeployCenterThemeNames -ThemesRoot $script:ThemesRoot) if ($availableThemes -notcontains $ThemeName) { return } try { $script:Theme = Import-DeployCenterTheme -ThemesRoot $script:ThemesRoot -ThemeName $ThemeName } catch { & $script:SourceLogAction ("Impossible de charger le theme '$ThemeName' : " + $_.Exception.Message) "ERROR" return } $script:CurrentTheme = $ThemeName $script:cmbTheme.BackColor = $script:Theme.Panel $script:cmbTheme.ForeColor = $script:Theme.Text $script:cmbTheme.Invalidate() $script:cmbTheme.Refresh() Set-ControlTheme -Control $script:form Set-ControlTheme -Control $script:logForm # Met a jour le logo si une variante propre au theme existe. Update-DeployCenterLogo -PictureBox $script:pictureLogo -ThemeName $script:CurrentTheme ` -LogoPath $script:LogoPath -LogoDarkPath $script:LogoDarkPath $script:lblTitle.ForeColor = $script:Theme.Text $script:lblSubtitle.ForeColor = $script:Theme.Secondary Set-DeployCenterButtonStyle -Button $script:btnChooseWindows -Theme $script:Theme -Role 'Button' Set-DeployCenterButtonStyle -Button $script:btnLog -Theme $script:Theme -Role 'Button' Set-DeployCenterButtonStyle -Button $script:btnRefresh -Theme $script:Theme -Role 'PrimaryButton' Set-DeployCenterButtonStyle -Button $script:btnDeploy -Theme $script:Theme -Role 'PrimaryButton' Set-DeployCenterButtonStyle -Button $script:btnClose -Theme $script:Theme -Role 'DangerButton' # Actualise explicitement le pied de page principal lors du changement de thème. foreach ($footer in $script:form.Controls.Find('DeployCenterSessionFooter', $true)) { $footer.BackColor = $script:Theme.PanelAlt $footer.ForeColor = $script:Theme.Secondary $footer.Invalidate() } $script:cmbTheme.BackColor = $script:Theme.Panel $script:cmbTheme.ForeColor = $script:Theme.Text $script:cmbTheme.Invalidate() $script:groupPC.Invalidate() $script:groupDisks.Invalidate() $script:cmbDisk.BackColor = $script:Theme.PanelAlt $script:cmbDisk.ForeColor = $script:Theme.Text $script:cmbDisk.Invalidate() # Le bouton reste au-dessus des autres controles de l'en-tete. $script:cmbTheme.BringToFront() # Forcer le rafraichissement apres le changement de palette. $script:form.SuspendLayout() try { foreach ($control in $script:form.Controls) { $control.Invalidate($true) } $script:form.Invalidate($true) $script:form.Refresh() } finally { $script:form.ResumeLayout($true) } } function Show-WindowsSourcesDialog { $dlg = New-Object System.Windows.Forms.Form $dlg.Text = 'Sources Windows - lecteur DeployCenter et partage SMB' $dlg.StartPosition = 'CenterParent' $dlg.Size = New-Object System.Drawing.Size(1100, 700) $dlg.MinimumSize = New-Object System.Drawing.Size(700, 450) Set-DeployCenterFormSizing -Form $dlg -Resizable # Ouvrir directement en plein écran pour exploiter toute la surface disponible. $dlg.WindowState = [System.Windows.Forms.FormWindowState]::Maximized $dlg.ShowInTaskbar = $false $dlg.BackColor = $script:Theme.Background $dlg.ForeColor = $script:Theme.Text $dlg.Font = $script:FontRegular $lblPath = New-Object System.Windows.Forms.Label $lblPath.Text = 'Chemins à analyser (séparés par ;) :' $lblPath.Location = New-Object System.Drawing.Point(16, 16) $lblPath.Size = New-Object System.Drawing.Size(260, 24) $lblPath.ForeColor = $script:Theme.Text $dlg.Controls.Add($lblPath) $txtPath = New-Object System.Windows.Forms.TextBox $txtPath.Location = New-Object System.Drawing.Point(16, 42) $txtPath.Size = New-Object System.Drawing.Size(560, 26) $txtPath.Anchor = 'Top,Left,Right' $defaultSourceRoot = $script:DeployVolumeRoot if ([string]::IsNullOrWhiteSpace($defaultSourceRoot)) { $defaultSourceRoot = $script:DeployRoot } $configuredPaths = [string]$script:Config.SourcePaths if ([string]::IsNullOrWhiteSpace($configuredPaths)) { $txtPath.Text = $defaultSourceRoot } else { $txtPath.Text = $configuredPaths.Replace("%DEPLOY_VOLUME%", $defaultSourceRoot) } $txtPath.BackColor = $script:Theme.PanelAlt $txtPath.ForeColor = $script:Theme.Text $dlg.Controls.Add($txtPath) $btnScan = New-Object System.Windows.Forms.Button $btnScan.Text = 'Rechercher' $btnScan.Location = New-Object System.Drawing.Point(650, 40) $btnScan.Size = New-Object System.Drawing.Size(100, 30) $btnScan.Anchor = 'Top,Right' $btnScan.UseVisualStyleBackColor = $false $btnScan.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $btnScan.FlatAppearance.BorderColor = $script:Theme.Border $btnScan.BackColor = $script:Theme.Accent $btnScan.ForeColor = [System.Drawing.Color]::White $dlg.Controls.Add($btnScan) $btnEditions = New-Object System.Windows.Forms.Button $btnEditions.Text = 'Afficher les éditions' $btnEditions.Location = New-Object System.Drawing.Point(760, 40) $btnEditions.Size = New-Object System.Drawing.Size(150, 30) $btnEditions.Anchor = 'Top,Right' $btnEditions.UseVisualStyleBackColor = $false $btnEditions.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $btnEditions.FlatAppearance.BorderColor = $script:Theme.Border $btnEditions.BackColor = $script:Theme.Panel $btnEditions.ForeColor = $script:Theme.Text $dlg.Controls.Add($btnEditions) $list = New-Object System.Windows.Forms.ListView $list.Location = New-Object System.Drawing.Point(16, 84) $list.Size = New-Object System.Drawing.Size(770, 420) $list.Anchor = 'Top,Bottom,Left,Right' $list.View = 'Details'; $list.FullRowSelect = $true; $list.GridLines = $true $list.MultiSelect = $false $list.HideSelection = $true $list.BackColor = $script:Theme.PanelAlt $list.ForeColor = $script:Theme.Text $list.OwnerDraw = $true [void]$list.Columns.Add('Type', 135) [void]$list.Columns.Add('Nom', 260) [void]$list.Columns.Add('Taille', 80) [void]$list.Columns.Add('Chemin', 250) # La colonne Nom est prioritaire : elle absorbe l'espace libre. $resizeSourceColumns = { if ($list.Columns.Count -ge 4) { $availableWidth = $list.ClientSize.Width - $list.Columns[0].Width - $list.Columns[2].Width - $list.Columns[3].Width - 4 if ($list.Items.Count -gt 0 -and $list.Items.Count -gt [math]::Floor($list.ClientSize.Height / 20)) { $availableWidth -= [System.Windows.Forms.SystemInformation]::VerticalScrollBarWidth } $list.Columns[1].Width = [Math]::Max(180, $availableWidth) } } $list.Add_SizeChanged($resizeSourceColumns) $list.Add_HandleCreated($resizeSourceColumns) # Dessin personnalise des en-tetes et des lignes pour que le ListView # respecte le theme actif au lieu d'utiliser les en-tetes natifs blancs. $list.Add_DrawColumnHeader({ param($sender, $e) $headerColor = if ($script:Theme.Contains('TableHeader')) { $script:Theme.TableHeader } else { $script:Theme.PanelAlt } $headerBrush = New-Object System.Drawing.SolidBrush($headerColor) $textBrush = New-Object System.Drawing.SolidBrush($script:Theme.Text) $borderPen = New-Object System.Drawing.Pen($script:Theme.Border) try { $e.Graphics.FillRectangle($headerBrush, $e.Bounds) $e.Graphics.DrawRectangle($borderPen, $e.Bounds.X, $e.Bounds.Y, $e.Bounds.Width - 1, $e.Bounds.Height - 1) $flags = [System.Windows.Forms.TextFormatFlags]::Left -bor [System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor [System.Windows.Forms.TextFormatFlags]::EndEllipsis [System.Windows.Forms.TextRenderer]::DrawText($e.Graphics, $e.Header.Text, $list.Font, $e.Bounds, $script:Theme.Text, $flags) } finally { $headerBrush.Dispose(); $textBrush.Dispose(); $borderPen.Dispose() } }) $list.Add_DrawItem({ param($sender, $e) if ($list.View -ne [System.Windows.Forms.View]::Details) { $e.DrawDefault = $true } }) $list.Add_DrawSubItem({ param($sender, $e) $rowBack = if (($e.Item.Index % 2) -eq 0) { $script:Theme.TableRowEven } else { $script:Theme.TableRowOdd } $rowFore = $script:Theme.Text # Ne surligner que l'element réellement sélectionné, jamais toutes les lignes. if ($e.Item.Selected -and $list.Focused) { $rowBack = $script:Theme.Accent $rowFore = [System.Drawing.Color]::White } $rowBrush = New-Object System.Drawing.SolidBrush($rowBack) $textBrush = New-Object System.Drawing.SolidBrush($rowFore) $borderPen = New-Object System.Drawing.Pen($script:Theme.Border) try { $e.Graphics.FillRectangle($rowBrush, $e.Bounds) $e.Graphics.DrawRectangle($borderPen, $e.Bounds.X, $e.Bounds.Y, $e.Bounds.Width - 1, $e.Bounds.Height - 1) $flags = [System.Windows.Forms.TextFormatFlags]::Left -bor [System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor [System.Windows.Forms.TextFormatFlags]::EndEllipsis -bor [System.Windows.Forms.TextFormatFlags]::NoPrefix [System.Windows.Forms.TextRenderer]::DrawText($e.Graphics, $e.SubItem.Text, $list.Font, $e.Bounds, $rowFore, $flags) } finally { $rowBrush.Dispose(); $textBrush.Dispose(); $borderPen.Dispose() } }) # Filtre local : il ne relance jamais l'analyse des lecteurs ou partages. $lblFilter = New-Object System.Windows.Forms.Label $lblFilter.Text = 'Filtrer la liste :' $lblFilter.Location = New-Object System.Drawing.Point(16, 80) $lblFilter.Size = New-Object System.Drawing.Size(100, 24) $lblFilter.ForeColor = $script:Theme.Text $dlg.Controls.Add($lblFilter) $txtFilter = New-Object System.Windows.Forms.TextBox $txtFilter.Location = New-Object System.Drawing.Point(120, 78) $txtFilter.Size = New-Object System.Drawing.Size(500, 26) $txtFilter.Anchor = 'Top,Left,Right' $txtFilter.BackColor = $script:Theme.PanelAlt $txtFilter.ForeColor = $script:Theme.Text $dlg.Controls.Add($txtFilter) $list.Location = New-Object System.Drawing.Point(16, 112) $dlg.Controls.Add($list) # Etat partage explicite entre les gestionnaires d'evenements WinForms. # En PowerShell, les callbacks peuvent s'executer dans une portee differente : # une variable locale $allFound peut alors rester vide dans le filtre. $sourceState = [hashtable]::Synchronized(@{ AllFound = @() }) $renderSourceList = { param([string]$Query) $previousSelection = $null if ($list.SelectedItems.Count -gt 0) { $previousSelection = [string]$list.SelectedItems[0].SubItems[3].Text } $needle = ([string]$Query).Trim() $visibleEntries = New-Object System.Collections.Generic.List[object] $entries = @($sourceState.AllFound) foreach ($entry in $entries) { if ([string]::IsNullOrWhiteSpace($needle)) { [void]$visibleEntries.Add($entry) continue } $searchable = '{0} {1} {2} {3} {4}' -f ` [string]$entry.Type, [string]$entry.Nom, [string]$entry.Chemin, ` [string]$entry.Taille, [string]$entry.Detail if ($searchable.IndexOf($needle, [System.StringComparison]::OrdinalIgnoreCase) -ge 0) { [void]$visibleEntries.Add($entry) } } $list.BeginUpdate() try { $list.Items.Clear() foreach ($entry in $visibleEntries) { $item = New-Object System.Windows.Forms.ListViewItem([string]$entry.Type) [void]$item.SubItems.Add([string]$entry.Nom) [void]$item.SubItems.Add([string]$entry.Taille) [void]$item.SubItems.Add([string]$entry.Chemin) if ($previousSelection -and ([string]$entry.Chemin -eq $previousSelection)) { $item.Selected = $true } [void]$list.Items.Add($item) } } finally { $list.EndUpdate() } if ($entries.Count -gt 0) { $lblStatus.Text = ('{0} résultat(s) affiché(s) sur {1}. Filtre instantané ; aucun fichier modifié.' -f $list.Items.Count, $entries.Count) } elseif ([string]::IsNullOrWhiteSpace($needle)) { $lblStatus.Text = 'Aucune source ISO/WIM/ESD ou installation extraite detectee dans les chemins accessibles.' } else { $lblStatus.Text = ('Aucun resultat pour « {0} ». Efface le filtre pour revoir la liste.' -f $needle) } } $txtFilter.Add_TextChanged({ & $renderSourceList $txtFilter.Text }) $lblStatus = New-Object System.Windows.Forms.Label $lblStatus.Text = 'Analyse en lecture seule du lecteur de DeployCenter et/ou du partage SMB. Plusieurs chemins peuvent etre separes par un point-virgule.' $lblStatus.Location = New-Object System.Drawing.Point(16, 515) $lblStatus.Size = New-Object System.Drawing.Size(770, 36) $lblStatus.Anchor = 'Bottom,Left,Right' $lblStatus.AutoSize = $false $lblStatus.ForeColor = $script:Theme.Secondary $dlg.Controls.Add($lblStatus) $progressAnalysis = New-Object System.Windows.Forms.ProgressBar $progressAnalysis.Name = 'progressWindowsSourceAnalysis' $progressAnalysis.Style = [System.Windows.Forms.ProgressBarStyle]::Marquee $progressAnalysis.MarqueeAnimationSpeed = 30 $progressAnalysis.Visible = $false $progressAnalysis.Anchor = 'Bottom,Right' $dlg.Controls.Add($progressAnalysis) # Recalculer les positions depuis la taille réelle de la fenêtre : # le tableau occupe l'espace restant et le statut reste toujours visible en bas. $resizeLayout = { $clientWidth = $dlg.ClientSize.Width $clientHeight = $dlg.ClientSize.Height $rightMargin = 16 $gap = 12 $btnWidth = 88 $editionsWidth = 148 $left = 12 $right = [Math]::Max($left + $btnWidth, $clientWidth - $rightMargin) $btnEditionsLeft = [Math]::Max($left, $right - $editionsWidth) $btnScanLeft = [Math]::Max($left, $btnEditionsLeft - $gap - $btnWidth) $txtPath.Width = [Math]::Max(100, $btnScanLeft - $left - $gap) $btnEditions.Location = New-Object System.Drawing.Point($btnEditionsLeft, 40) $btnEditions.Width = [Math]::Max(120, $right - $btnEditionsLeft) $btnScan.Location = New-Object System.Drawing.Point($btnScanLeft, 40) $btnScan.Width = [Math]::Max(80, $btnEditionsLeft - $gap - $btnScanLeft) $btnScan.Anchor = 'Top,Right' $btnEditions.Anchor = 'Top,Right' $txtPath.Anchor = 'Top,Left,Right' $lblFilter.Location = New-Object System.Drawing.Point(16, 80) $txtFilter.Location = New-Object System.Drawing.Point(120, 78) $txtFilter.Size = New-Object System.Drawing.Size([Math]::Max(180, $clientWidth - 152), 26) $list.Location = New-Object System.Drawing.Point(16, 112) $list.Size = New-Object System.Drawing.Size([Math]::Max(300, $clientWidth - 32), [Math]::Max(120, $clientHeight - 205)) $list.Anchor = 'Top,Bottom,Left,Right' $lblStatus.Location = New-Object System.Drawing.Point(16, ($clientHeight - 52)) $lblStatus.Size = New-Object System.Drawing.Size([Math]::Max(150, $clientWidth - 164), 24) $lblStatus.Anchor = 'Bottom,Left,Right' $progressAnalysis.Location = New-Object System.Drawing.Point(($clientWidth - 136), ($clientHeight - 52)) $progressAnalysis.Size = New-Object System.Drawing.Size(120, 20) } $dlg.Add_Shown({ & $resizeLayout # Lancer automatiquement la première analyse à l'ouverture. # Le bouton Rechercher reste disponible si l'utilisateur change les chemins. $btnScan.PerformClick() }) $dlg.Add_SizeChanged({ & $resizeLayout }) $btnEditions.Add_Click({ if ($list.SelectedItems.Count -eq 0) { Show-DeployCenterMessage -Message 'Sélectionne d''abord une source dans la liste.' -Title 'Éditions Windows' -Icon Information -Owner $dlg -Theme $script:Theme -Font $script:FontRegular return } $selectedPath = [string]$list.SelectedItems[0].SubItems[3].Text $selectedName = [string]$list.SelectedItems[0].SubItems[1].Text $resolvedImage = $null $mountTransferred = $false $btnEditions.Enabled = $false $btnScan.Enabled = $false $dlg.Cursor = [System.Windows.Forms.Cursors]::WaitCursor $lblStatus.Text = "Analyse des editions de $selectedName en cours..." $progressAnalysis.Visible = $true $progressAnalysis.BringToFront() $dlg.Refresh() try { $resolvedImage = Resolve-InstallImagePath -SelectedPath $selectedPath -ExistingImage $script:SelectedWindowsEdition $imagePath = [string]$resolvedImage.ImagePath $editionResult = Get-WindowsImageEditions -ImagePath $imagePath -LogAction $script:SourceLogAction $editions = @($editionResult.Editions) $globalImageVersion = [string]$editionResult.GlobalVersion $lines = foreach ($edition in $editions) { $index = if ($edition.ImageIndex) { $edition.ImageIndex } elseif ($edition.Index) { $edition.Index } else { '?' } $name = if ($edition.ImageName) { $edition.ImageName } elseif ($edition.Name) { $edition.Name } else { 'Nom non disponible' } $arch = if ($edition.Architecture) { [string]$edition.Architecture } else { 'Architecture non disponible' } $version = if ($edition.Version) { [string]$edition.Version } else { 'Version non disponible' } "Index : $index`r`nNom : $name`r`nArchitecture : $arch`r`nVersion : $version" } # Le formulaire enfant est modal : actualiser le statut avant son affichage, # sinon le formulaire parent reste visuellement sur « analyse en cours ». $lblStatus.Text = "$($editions.Count) édition(s) détectée(s) dans $selectedName. Sélectionne une édition." $dlg.Refresh() # Tableau des editions ; l'index DISM selectionne est conserve pour la suite. $resultForm = New-Object System.Windows.Forms.Form $resultForm.Text = 'Éditions Windows disponibles' $resultForm.StartPosition = 'CenterParent' $resultForm.Size = New-Object System.Drawing.Size(700, 480) $resultForm.MinimumSize = New-Object System.Drawing.Size(520, 320) Set-DeployCenterFormSizing -Form $resultForm $resultForm.ShowInTaskbar = $false $resultForm.BackColor = $script:Theme.Background $resultForm.ForeColor = $script:Theme.Text $sourceLabel = New-Object System.Windows.Forms.Label $sourceLabel.Text = "Source : $selectedPath" $sourceLabel.Dock = [System.Windows.Forms.DockStyle]::Top $sourceLabel.Height = 38 $sourceLabel.Padding = New-Object System.Windows.Forms.Padding(10, 8, 10, 4) $sourceLabel.AutoEllipsis = $true $sourceLabel.BackColor = $script:Theme.Background $sourceLabel.ForeColor = $script:Theme.Text $editionList = New-Object System.Windows.Forms.ListView $editionList.View = [System.Windows.Forms.View]::Details $editionList.FullRowSelect = $true $editionList.GridLines = $true $editionList.MultiSelect = $false $editionList.HideSelection = $false # Une seule édition peut être sélectionnée à la fois. $editionList.Sorting = [System.Windows.Forms.SortOrder]::None $editionList.Dock = [System.Windows.Forms.DockStyle]::Fill $editionList.BackColor = $script:Theme.Panel $editionList.ForeColor = $script:Theme.Text [void]$editionList.Columns.Add('Index', 65) [void]$editionList.Columns.Add('Édition', 260) [void]$editionList.Columns.Add('Architecture', 100) [void]$editionList.Columns.Add('Version', 105) # Édition est la colonne prioritaire : Version conserve une largeur fixe. $resizeEditionColumns = { if ($editionList.Columns.Count -ge 4) { $availableWidth = $editionList.ClientSize.Width - $editionList.Columns[0].Width - $editionList.Columns[2].Width - $editionList.Columns[3].Width - 4 if ($editionList.Items.Count -gt 0 -and $editionList.Items.Count -gt [Math]::Floor($editionList.ClientSize.Height / 20)) { $availableWidth -= [System.Windows.Forms.SystemInformation]::VerticalScrollBarWidth } $editionList.Columns[1].Width = [Math]::Max(220, $availableWidth) } } $editionList.Add_SizeChanged($resizeEditionColumns) $resultForm.Add_Shown($resizeEditionColumns) # Dessin personnalise des en-tetes et cellules pour que ListView # respecte le theme Light/Dark au lieu de garder un en-tete blanc. $editionList.OwnerDraw = $true $editionList.Add_DrawColumnHeader({ param($sender, $e) $headerColor = if ($script:Theme.Contains('TableHeader')) { $script:Theme.TableHeader } else { $script:Theme.PanelAlt } $headerBrush = New-Object System.Drawing.SolidBrush($headerColor) $headerPen = New-Object System.Drawing.Pen($script:Theme.Border) try { $e.Graphics.FillRectangle($headerBrush, $e.Bounds) $e.Graphics.DrawRectangle($headerPen, $e.Bounds.X, $e.Bounds.Y, $e.Bounds.Width - 1, $e.Bounds.Height - 1) [System.Windows.Forms.TextRenderer]::DrawText( $e.Graphics, $e.Header.Text, $sender.Font, $e.Bounds, $script:Theme.Text, ([System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor [System.Windows.Forms.TextFormatFlags]::Left -bor [System.Windows.Forms.TextFormatFlags]::EndEllipsis) ) } finally { $headerBrush.Dispose() $headerPen.Dispose() } }) $editionList.Add_DrawItem({ param($sender, $e) }) $editionList.Add_DrawSubItem({ param($sender, $e) $cellBack = if (($e.Item.Index % 2) -eq 0) { $script:Theme.TableRowEven } else { $script:Theme.TableRowOdd } $cellFore = $script:Theme.Text if ($e.Item.Selected) { $cellBack = $script:Theme.Accent $cellFore = [System.Drawing.Color]::White } $cellBrush = New-Object System.Drawing.SolidBrush($cellBack) $cellPen = New-Object System.Drawing.Pen($script:Theme.Border) try { $e.Graphics.FillRectangle($cellBrush, $e.Bounds) if ($sender.GridLines) { $e.Graphics.DrawRectangle($cellPen, $e.Bounds.X, $e.Bounds.Y, $e.Bounds.Width - 1, $e.Bounds.Height - 1) } [System.Windows.Forms.TextRenderer]::DrawText( $e.Graphics, $e.SubItem.Text, $sender.Font, $e.Bounds, $cellFore, ([System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor [System.Windows.Forms.TextFormatFlags]::Left -bor [System.Windows.Forms.TextFormatFlags]::EndEllipsis) ) } finally { $cellBrush.Dispose() $cellPen.Dispose() } }) foreach ($edition in $editions) { $index = if ($edition.ImageIndex) { [string]$edition.ImageIndex } elseif ($edition.Index) { [string]$edition.Index } else { '?' } $name = if ($edition.ImageName) { [string]$edition.ImageName } elseif ($edition.Name) { [string]$edition.Name } elseif ($edition.ImageDescription) { [string]$edition.ImageDescription } else { 'Nom non disponible' } $archValue = $null foreach ($propertyName in @('Architecture', 'ImageArchitecture')) { if ($edition.PSObject.Properties[$propertyName] -and $edition.$propertyName) { $archValue = $edition.$propertyName break } } $arch = if ($null -ne $archValue) { switch ([string]$archValue) { '0' { 'x86' } '5' { 'ARM' } '9' { 'x64' } '12' { 'ARM64' } default { [string]$archValue } } } else { 'Non disponible' } $version = if ($edition.Version) { [string]$edition.Version } else { 'Non disponible' } $row = New-Object System.Windows.Forms.ListViewItem($index) [void]$row.SubItems.Add($name) [void]$row.SubItems.Add($arch) [void]$row.SubItems.Add($version) $row.Tag = $edition [void]$editionList.Items.Add($row) } $buttonPanel = New-Object System.Windows.Forms.Panel $buttonPanel.Dock = [System.Windows.Forms.DockStyle]::Bottom $buttonPanel.Height = 52 $buttonPanel.BackColor = $script:Theme.Background $cancelButton = New-Object System.Windows.Forms.Button $cancelButton.Text = 'Annuler' $cancelButton.Size = New-Object System.Drawing.Size(100, 30) $cancelButton.Anchor = 'Right,Top' $cancelButton.Location = New-Object System.Drawing.Point(0, 10) $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $validateButton = New-Object System.Windows.Forms.Button $validateButton.Text = 'Valider l''édition' $validateButton.Size = New-Object System.Drawing.Size(140, 30) $validateButton.Anchor = 'Right,Top' $validateButton.Location = New-Object System.Drawing.Point(0, 10) $validateButton.Enabled = $false $editionList.Add_SelectedIndexChanged({ $validateButton.Enabled = ($editionList.SelectedItems.Count -gt 0 -and $editionList.SelectedItems[0].SubItems[0].Text -ne '?') }) $validateButton.Add_Click({ if ($editionList.SelectedItems.Count -gt 0) { $resultForm.Tag = [pscustomobject]@{ SourcePath = $selectedPath ImagePath = $imagePath MountedImage = $resolvedImage.MountedImage Edition = $editionList.SelectedItems[0].Tag Index = [int]$editionList.SelectedItems[0].SubItems[0].Text Name = $editionList.SelectedItems[0].SubItems[1].Text } $resultForm.DialogResult = [System.Windows.Forms.DialogResult]::OK $resultForm.Close() } }) $editionList.Add_DoubleClick({ if ($editionList.SelectedItems.Count -gt 0 -and $validateButton.Enabled) { $validateButton.PerformClick() } }) $buttonPanel.Controls.Add($cancelButton) $buttonPanel.Controls.Add($validateButton) $buttonPanel.Add_Resize({ $validateButton.Location = New-Object System.Drawing.Point(($buttonPanel.ClientSize.Width - $validateButton.Width - 12), 10) $cancelButton.Location = New-Object System.Drawing.Point(($validateButton.Left - $cancelButton.Width - 8), 10) }) $resultForm.Controls.Add($editionList) $resultForm.Controls.Add($buttonPanel) $resultForm.Controls.Add($sourceLabel) $resultForm.AcceptButton = $validateButton $resultForm.CancelButton = $cancelButton Add-SessionFooter -TargetForm $resultForm -Theme $script:Theme -Font $script:FontSmall ` -IPv4 $script:DeployIPv4 -VncPassword $script:VncPassword -ShowFooter $false $dialogResult = $resultForm.ShowDialog($dlg) $chosenEdition = $resultForm.Tag $resultForm.Dispose() if ($dialogResult -eq [System.Windows.Forms.DialogResult]::OK -and $chosenEdition) { if ($script:SelectedWindowsEdition -and -not [string]::Equals([string]$script:SelectedWindowsEdition.SourcePath, [string]$chosenEdition.SourcePath, [StringComparison]::OrdinalIgnoreCase)) { [void](Dismount-DeployCenterInstallImage -Image $script:SelectedWindowsEdition) } $script:SelectedWindowsEdition = $chosenEdition $mountTransferred = $true $lblStatus.Text = "Édition sélectionnée : $($chosenEdition.Name) (index $($chosenEdition.Index))." & $script:SourceLogAction "Edition selectionnee : $($chosenEdition.Name), index $($chosenEdition.Index), image $imagePath" 'SUCCESS' $dlg.DialogResult = [System.Windows.Forms.DialogResult]::OK $dlg.Close() } else { $lblStatus.Text = "$($editions.Count) édition(s) trouvée(s) dans $selectedName. Aucune nouvelle édition sélectionnée." } & $script:SourceLogAction "Analyse des editions terminee : $imagePath ($($editions.Count) edition(s))." 'SUCCESS' } catch { $lblStatus.Text = "Echec de l'analyse des editions de $selectedName." & $script:SourceLogAction "Erreur analyse editions $selectedPath : $($_.Exception.Message)" 'ERROR' Show-DeployCenterMessage -Message $_.Exception.Message -Title 'Analyse des éditions' -Icon Warning -Owner $dlg -Theme $script:Theme -Font $script:FontRegular } finally { if ($resolvedImage -and $resolvedImage.MountedImage -and -not $mountTransferred -and (-not $script:SelectedWindowsEdition -or $resolvedImage.MountedImage -ne $script:SelectedWindowsEdition.MountedImage)) { try { [void](Dismount-DeployCenterInstallImage -Image $resolvedImage) } catch { & $script:SourceLogAction "Impossible de démonter l'ISO après l'analyse : $($_.Exception.Message)" 'WARNING' } } $dlg.Cursor = [System.Windows.Forms.Cursors]::Default $progressAnalysis.Visible = $false $btnEditions.Enabled = $true $btnScan.Enabled = $true } }) $list.Add_DoubleClick({ if ($list.SelectedItems.Count -gt 0 -and $btnEditions.Enabled) { $btnEditions.PerformClick() } }) $btnScan.Add_Click({ $btnScan.Enabled = $false $dlg.Cursor = [System.Windows.Forms.Cursors]::WaitCursor $lblStatus.Text = 'Recherche en cours sur les chemins indiques...' $sourceState.AllFound = @() $list.Items.Clear() try { # La recherche ne modifie jamais DeployCenter.ini. $sourceState.AllFound = @(Find-WindowsSources -RootPath $txtPath.Text -LogAction $script:SourceLogAction) & $renderSourceList $txtFilter.Text if (@($sourceState.AllFound).Count -eq 0) { $lblStatus.Text = 'Aucune source ISO/WIM/ESD ou installation extraite detectee dans les chemins accessibles.' & $script:SourceLogAction 'Aucune source Windows detectee dans les chemins accessibles.' 'WARNING' } } catch { $lblStatus.Text = 'Echec de la recherche. Consulte le message.' & $script:SourceLogAction "Erreur detection sources : $($_.Exception.Message)" 'ERROR' Show-DeployCenterMessage -Message $_.Exception.Message -Title 'Détection des sources' -Icon Warning -Owner $dlg -Theme $script:Theme -Font $script:FontRegular } finally { $dlg.Cursor = [System.Windows.Forms.Cursors]::Default $btnScan.Enabled = $true } }) Add-SessionFooter -TargetForm $dlg -Theme $script:Theme -Font $script:FontSmall ` -IPv4 $script:DeployIPv4 -VncPassword $script:VncPassword [void]$dlg.ShowDialog($script:form) $dlg.Dispose() } function Update-HardwareView { $script:btnRefresh.Enabled = $false $script:form.Cursor = [System.Windows.Forms.Cursors]::WaitCursor try { if (-not (Get-Command Get-HardwareInfo -ErrorAction SilentlyContinue)) { throw 'Le module HardwareInventory ne fournit pas Get-HardwareInfo.' } $info = Get-HardwareInfo $script:lblManufacturer.Text = "Fabricant : $($info.Manufacturer)" $script:lblModel.Text = "Modèle : $($info.Model)" $script:lblSerial.Text = "Numéro de série : $($info.SerialNumber)" $script:lblFirmware.Text = "Firmware : $($info.Firmware)" $script:lblArchitecture.Text = "Architecture : $($info.Architecture)" $script:HardwareInventory = $info $previousDiskIndex = $null if ($null -ne $script:cmbDisk.SelectedItem -and $null -ne $script:cmbDisk.SelectedItem.Tag) { $previousDiskIndex = [string]$script:cmbDisk.SelectedItem.Tag } $script:RefreshingDiskList = $true $script:cmbDisk.BeginUpdate() try { $script:cmbDisk.Items.Clear() foreach ($disk in $info.Disks) { $diskLabel = "Disque {0} - {1} - {2:N1} Go - {3} - {4}" -f $disk.Index, $disk.Model, $disk.SizeGB, $disk.BusType, $disk.Status $diskChoice = [pscustomobject]@{ Text = $diskLabel; Tag = [string]$disk.Index } [void]$script:cmbDisk.Items.Add($diskChoice) } $script:cmbDisk.DisplayMember = 'Text' if ($script:cmbDisk.Items.Count -gt 0) { $selectedIndex = -1 if ($null -ne $previousDiskIndex) { for ($i = 0; $i -lt $script:cmbDisk.Items.Count; $i++) { if ([string]$script:cmbDisk.Items[$i].Tag -eq $previousDiskIndex) { $selectedIndex = $i; break } } } if ($selectedIndex -lt 0 -and $script:cmbDisk.Items.Count -eq 1) { $selectedIndex = 0 } $script:cmbDisk.SelectedIndex = $selectedIndex } } finally { $script:cmbDisk.EndUpdate() $script:RefreshingDiskList = $false } $script:SelectedDiskIndex = if ($script:cmbDisk.SelectedIndex -ge 0) { [string]$script:cmbDisk.SelectedItem.Tag } else { $null } Write-DeployInventory -InventoryDir $script:InventoryDir -InventoryFile $script:InventoryFile -HardwareInfo $info -DeploymentIPv4 $script:DeployIPv4 -VncPassword $script:VncPassword -LogAction $script:SourceLogAction & $script:SourceLogAction "Inventaire materiel actualise." "SUCCESS" foreach ($errorMessage in $info.Errors) { & $script:SourceLogAction $errorMessage "WARNING" } if ($info.Disks.Count -eq 0) { & $script:SourceLogAction "Aucun disque physique detecte." "WARNING" } } catch { & $script:SourceLogAction "Erreur inventaire : $($_.Exception.Message)" "ERROR" Show-DeployCenterMessage -Message $_.Exception.Message -Title 'Erreur DeployCenter' -Icon Error -Owner $script:form -Theme $script:Theme -Font $script:FontRegular } finally { $script:btnRefresh.Enabled = $true $script:form.Cursor = [System.Windows.Forms.Cursors]::Default } } function Get-PartitionProfileSizingSelection { param( [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Profile, [Parameter(Mandatory=$true)]$DiskInfo, [System.Collections.IDictionary]$InitialValues = @{} ) $capacity = Get-DeployCenterPartitionSizingCapacity -Profile $Profile -DiskSizeBytes ([long]$DiskInfo.SizeBytes) return Show-DeployCenterPartitionSizingDialog ` -Profile $Profile ` -AvailableGB $capacity.UsableGB ` -Theme $script:Theme ` -Font $script:FontRegular ` -Owner $script:form ` -InitialValues $InitialValues } function Set-PartitionProfileSizingSelection { param( [Parameter(Mandatory=$true)][System.Collections.IDictionary]$Profile, [Parameter(Mandatory=$true)]$DiskInfo, [System.Collections.IDictionary]$InitialValues = @{} ) $selection = Get-PartitionProfileSizingSelection -Profile $Profile -DiskInfo $DiskInfo -InitialValues $InitialValues if ($null -eq $selection) { return $false } $script:SelectedPartitionSizing = New-DeployCenterPartitionSizingState -Profile $Profile -DiskInfo $DiskInfo -Selection $selection return $true } function Update-DeployCenterLayout { if ($null -eq $script:form -or $script:form.IsDisposed) { return } $w = $script:form.ClientSize.Width $h = $script:form.ClientSize.Height $m = 24 $contentWidth = [Math]::Max(300, $w - (2 * $m)) # En-tete : le selecteur de theme reste accroche au bord droit. if ($null -ne $script:cmbTheme) { $script:cmbTheme.Location = New-Object System.Drawing.Point([Math]::Max($m, $w - $m - $script:cmbTheme.Width), 25) } # Les deux panneaux superieurs conservent leur hauteur, mais s'etirent en largeur. $script:groupPC.Location = New-Object System.Drawing.Point($m, 100) $script:groupPC.Size = New-Object System.Drawing.Size($contentWidth, 90) $script:groupDisks.Location = New-Object System.Drawing.Point($m, 205) $script:groupDisks.Size = New-Object System.Drawing.Size($contentWidth, 270) Set-DiskSelectorWidth $footerHeight = 26 $buttonHeightLocal = 38 $buttonYLocal = $h - $footerHeight - 14 - $buttonHeightLocal $buttonWidthLocal = 140 $buttonGapLocal = 12 $script:btnClose.Size = New-Object System.Drawing.Size($buttonWidthLocal, $buttonHeightLocal) $script:btnRefresh.Size = New-Object System.Drawing.Size($buttonWidthLocal, $buttonHeightLocal) $script:btnDeploy.Size = New-Object System.Drawing.Size($buttonWidthLocal, $buttonHeightLocal) $script:btnLog.Size = New-Object System.Drawing.Size($buttonWidthLocal, $buttonHeightLocal) $script:btnClose.Location = New-Object System.Drawing.Point([Math]::Max($m, $w - $m - $buttonWidthLocal), $buttonYLocal) $script:btnDeploy.Location = New-Object System.Drawing.Point([Math]::Max($m, $script:btnClose.Left - $buttonGapLocal - $buttonWidthLocal), $buttonYLocal) $script:btnRefresh.Location = New-Object System.Drawing.Point([Math]::Max($m, $script:btnDeploy.Left - $buttonGapLocal - $buttonWidthLocal), $buttonYLocal) $script:btnLog.Location = New-Object System.Drawing.Point($m, $buttonYLocal) Set-DiskSelectorWidth }