Ajout de l'installation de Windows Correction du chargement des images iso. Correction de la définition de la taille de WinRE.
1520 lines
72 KiB
PowerShell
1520 lines
72 KiB
PowerShell
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
|
||
|
||
$hostLabel = New-Object System.Windows.Forms.Label
|
||
$hostLabel.Text = "Nom d’hôte"
|
||
$hostLabel.Location = New-Object System.Drawing.Point(12, 190)
|
||
$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), 187)
|
||
$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
|
||
|
||
$Parent.Controls.AddRange(@($diskLabel, $diskCombo, $systemLabel, $chooseSystemButton, $selectedSystemLabel, $hostLabel, $hostTextBox))
|
||
return [pscustomobject]@{
|
||
DiskComboBox = $diskCombo
|
||
ChooseSystemButton = $chooseSystemButton
|
||
SelectedSystemLabel = $selectedSystemLabel
|
||
PartitionProfileLabel = $profileSelector.Label
|
||
PartitionProfileComboBox = $profileSelector.ComboBox
|
||
HostNameTextBox = $hostTextBox
|
||
}
|
||
}
|
||
|
||
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.HostNameTextBox.Location = New-Object System.Drawing.Point([Math]::Max(244, $Parent.ClientSize.Width - 202), 187)
|
||
$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-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
|
||
|
||
if ($script:lblWinPE.Text -like "*WinPE*") {
|
||
$script:lblWinPE.ForeColor = $script:Theme.Success
|
||
}
|
||
else {
|
||
$script:lblWinPE.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)"
|
||
|
||
if ($info.WinPE) {
|
||
$script:lblWinPE.Text = "Environnement : WinPE"
|
||
$script:lblWinPE.ForeColor = $script:Theme.Success
|
||
}
|
||
else {
|
||
$script:lblWinPE.Text = "Environnement : Windows classique"
|
||
$script:lblWinPE.ForeColor = $script:Theme.Secondary
|
||
}
|
||
|
||
$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, 105)
|
||
$script:groupDisks.Location = New-Object System.Drawing.Point($m, 220)
|
||
$script:groupDisks.Size = New-Object System.Drawing.Size($contentWidth, 226)
|
||
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
|
||
}
|