mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-13 18:07:20 -06:00
Add support for SerialComputerNames CSV mapping
Introduces a new `SerialComputerNames` device naming mode that allows automated device naming during deployment based on the BIOS serial number. The mapping is provided via a CSV file with `SerialNumber` and `ComputerName` columns. This feature requires `CopyUnattend` and writes a `SerialComputerNames.csv` file to the USB deployment media, replacing the need for manual prompts or prefix selection when device serial numbers are known in advance. The UI has been updated to support creating, loading, and saving the CSV mapping content.
This commit is contained in:
@@ -73,7 +73,7 @@ When set to $true, will copy the provisioning package from the $FFUDevelopmentPa
|
||||
When set to $true, stages the selected architecture-specific unattend XML file as Unattend.xml on the deployment partition of the USB drive. Default is $false.
|
||||
|
||||
.PARAMETER DeviceNamingMode
|
||||
Controls how device naming is handled when unattend content is copied to USB media or injected into the FFU. Supported values are Legacy, None, Prompt, Template, and Prefixes.
|
||||
Controls how device naming is handled when unattend content is copied to USB media or injected into the FFU. Supported values are Legacy, None, Prompt, Template, Prefixes, and SerialComputerNames.
|
||||
|
||||
.PARAMETER DeviceNameTemplate
|
||||
Sets the device name used when DeviceNamingMode is Template. Supports a static name or the %serial% token when CopyUnattend is used.
|
||||
@@ -84,6 +84,12 @@ Sets the prefixes used when DeviceNamingMode is Prefixes. Each entry becomes a l
|
||||
.PARAMETER DeviceNamePrefixesPath
|
||||
Path to the source prefixes file used for legacy copy or when DeviceNamePrefixes is not supplied. Default is $FFUDevelopmentPath\Unattend\prefixes.txt.
|
||||
|
||||
.PARAMETER DeviceNameSerialComputerNames
|
||||
Sets the CSV content used when DeviceNamingMode is SerialComputerNames. The CSV must include SerialNumber and ComputerName headers.
|
||||
|
||||
.PARAMETER DeviceNameSerialComputerNamesPath
|
||||
Path to the source CSV file used when DeviceNamingMode is SerialComputerNames and DeviceNameSerialComputerNames is not supplied. Default is $FFUDevelopmentPath\Unattend\SerialComputerNames.csv.
|
||||
|
||||
.PARAMETER UnattendX64FilePath
|
||||
Path to the x64 unattend XML source file. Default is $FFUDevelopmentPath\Unattend\unattend_x64.xml.
|
||||
|
||||
@@ -425,11 +431,13 @@ param(
|
||||
[bool]$AllowVHDXCaching,
|
||||
[bool]$CopyPPKG,
|
||||
[bool]$CopyUnattend,
|
||||
[ValidateSet('Legacy', 'None', 'Prompt', 'Template', 'Prefixes')]
|
||||
[ValidateSet('Legacy', 'None', 'Prompt', 'Template', 'Prefixes', 'SerialComputerNames')]
|
||||
[string]$DeviceNamingMode = 'Legacy',
|
||||
[string]$DeviceNameTemplate,
|
||||
[string[]]$DeviceNamePrefixes,
|
||||
[string]$DeviceNamePrefixesPath,
|
||||
[string[]]$DeviceNameSerialComputerNames,
|
||||
[string]$DeviceNameSerialComputerNamesPath,
|
||||
[string]$UnattendX64FilePath,
|
||||
[string]$UnattendArm64FilePath,
|
||||
[bool]$CopyAutopilot,
|
||||
@@ -644,7 +652,7 @@ function Save-StagedUnattendFile {
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$DestinationPath,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet('Legacy', 'None', 'Prompt', 'Template', 'Prefixes')]
|
||||
[ValidateSet('Legacy', 'None', 'Prompt', 'Template', 'Prefixes', 'SerialComputerNames')]
|
||||
[string]$DeviceNamingMode,
|
||||
[string]$DeviceNameTemplate,
|
||||
[Parameter(Mandatory = $true)]
|
||||
@@ -685,6 +693,11 @@ function Save-StagedUnattendFile {
|
||||
$computerNamePath.ComputerNameElement.InnerText = '*'
|
||||
}
|
||||
}
|
||||
elseif ($DeviceNamingMode -eq 'SerialComputerNames') {
|
||||
if ($computerNamePath.CreatedComputerNameElement) {
|
||||
$computerNamePath.ComputerNameElement.InnerText = '*'
|
||||
}
|
||||
}
|
||||
elseif (($DeviceNamingMode -eq 'Legacy') -and $computerNamePath.CreatedComputerNameElement) {
|
||||
$computerNamePath.ComputerNameElement.InnerText = if ($LegacyPrefixesWillBeStaged) { '*' } else { 'MyComputer' }
|
||||
}
|
||||
@@ -707,12 +720,24 @@ $resolvedDeviceNamePrefixesPath = if ([string]::IsNullOrWhiteSpace($DeviceNamePr
|
||||
else {
|
||||
$DeviceNamePrefixesPath
|
||||
}
|
||||
$effectiveDeviceNameSerialComputerNames = @($DeviceNameSerialComputerNames | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim() })
|
||||
$resolvedDeviceNameSerialComputerNamesPath = if ([string]::IsNullOrWhiteSpace($DeviceNameSerialComputerNamesPath)) {
|
||||
Join-Path (Join-Path $FFUDevelopmentPath 'Unattend') 'SerialComputerNames.csv'
|
||||
}
|
||||
else {
|
||||
$DeviceNameSerialComputerNamesPath
|
||||
}
|
||||
|
||||
if (($DeviceNamingMode -eq 'Prefixes') -and ($effectiveDeviceNamePrefixes.Count -eq 0) -and (Test-Path -Path $resolvedDeviceNamePrefixesPath -PathType Leaf)) {
|
||||
$effectiveDeviceNamePrefixes = @(Get-Content -Path $resolvedDeviceNamePrefixesPath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim() })
|
||||
WriteLog "Loaded device name prefixes from $resolvedDeviceNamePrefixesPath"
|
||||
}
|
||||
|
||||
if (($DeviceNamingMode -eq 'SerialComputerNames') -and ($effectiveDeviceNameSerialComputerNames.Count -eq 0) -and (Test-Path -Path $resolvedDeviceNameSerialComputerNamesPath -PathType Leaf)) {
|
||||
$effectiveDeviceNameSerialComputerNames = @(Get-Content -Path $resolvedDeviceNameSerialComputerNamesPath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim() })
|
||||
WriteLog "Loaded serial computer-name mappings from $resolvedDeviceNameSerialComputerNamesPath"
|
||||
}
|
||||
|
||||
if ($CopyUnattend -and $InjectUnattend) {
|
||||
throw 'CopyUnattend and InjectUnattend cannot both be set to `$true. Select only one unattend delivery method.'
|
||||
}
|
||||
@@ -749,6 +774,38 @@ elseif ($DeviceNamingMode -eq 'Prefixes') {
|
||||
throw 'DeviceNamingMode Prefixes requires at least one DeviceNamePrefixes entry or a valid DeviceNamePrefixesPath.'
|
||||
}
|
||||
}
|
||||
elseif ($DeviceNamingMode -eq 'SerialComputerNames') {
|
||||
if (-not $CopyUnattend) {
|
||||
throw 'DeviceNamingMode SerialComputerNames requires CopyUnattend. Serial-to-computer-name mapping is not supported with InjectUnattend.'
|
||||
}
|
||||
|
||||
if ($effectiveDeviceNameSerialComputerNames.Count -eq 0) {
|
||||
throw 'DeviceNamingMode SerialComputerNames requires DeviceNameSerialComputerNames content or a valid DeviceNameSerialComputerNamesPath.'
|
||||
}
|
||||
|
||||
try {
|
||||
$serialComputerNameMappings = @($effectiveDeviceNameSerialComputerNames | ConvertFrom-Csv -ErrorAction Stop)
|
||||
}
|
||||
catch {
|
||||
throw "DeviceNamingMode SerialComputerNames requires valid CSV content with SerialNumber and ComputerName headers. $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
if ($serialComputerNameMappings.Count -eq 0) {
|
||||
throw 'DeviceNamingMode SerialComputerNames requires at least one CSV data row.'
|
||||
}
|
||||
|
||||
$serialComputerNameHeaders = @($serialComputerNameMappings[0].PSObject.Properties.Name)
|
||||
if ((-not ($serialComputerNameHeaders -contains 'SerialNumber')) -or (-not ($serialComputerNameHeaders -contains 'ComputerName'))) {
|
||||
throw 'DeviceNamingMode SerialComputerNames requires SerialNumber and ComputerName headers.'
|
||||
}
|
||||
|
||||
$validSerialComputerNameMappings = @($serialComputerNameMappings | Where-Object {
|
||||
-not [string]::IsNullOrWhiteSpace([string]$_.SerialNumber) -and -not [string]::IsNullOrWhiteSpace([string]$_.ComputerName)
|
||||
})
|
||||
if ($validSerialComputerNameMappings.Count -eq 0) {
|
||||
throw 'DeviceNamingMode SerialComputerNames requires at least one row with both SerialNumber and ComputerName values.'
|
||||
}
|
||||
}
|
||||
|
||||
# Validate that the selected Windows SKU is compatible with the chosen Windows release and ensure an ISO is provided for unsupported releases
|
||||
$clientSKUs = @(
|
||||
@@ -4570,6 +4627,11 @@ Function New-DeploymentUSB {
|
||||
$computerNamePath.ComputerNameElement.InnerText = '*'
|
||||
}
|
||||
}
|
||||
elseif ($DeviceNamingMode -eq 'SerialComputerNames') {
|
||||
if ($computerNamePath.CreatedComputerNameElement) {
|
||||
$computerNamePath.ComputerNameElement.InnerText = '*'
|
||||
}
|
||||
}
|
||||
elseif (($DeviceNamingMode -eq 'Legacy') -and $computerNamePath.CreatedComputerNameElement) {
|
||||
$computerNamePath.ComputerNameElement.InnerText = if ($LegacyPrefixesWillBeStaged) { '*' } else { 'MyComputer' }
|
||||
}
|
||||
@@ -4644,6 +4706,10 @@ Function New-DeploymentUSB {
|
||||
WriteLog "Writing prefixes.txt file to $UnattendPathOnUSB"
|
||||
$using:effectiveDeviceNamePrefixes | Set-Content -Path (Join-Path $UnattendPathOnUSB 'prefixes.txt') -Encoding UTF8
|
||||
}
|
||||
elseif ($using:DeviceNamingMode -eq 'SerialComputerNames') {
|
||||
WriteLog "Writing SerialComputerNames.csv file to $UnattendPathOnUSB"
|
||||
$using:effectiveDeviceNameSerialComputerNames | Set-Content -Path (Join-Path $UnattendPathOnUSB 'SerialComputerNames.csv') -Encoding UTF8
|
||||
}
|
||||
elseif ($legacyPrefixesWillBeStaged) {
|
||||
WriteLog "Copying prefixes.txt file to $UnattendPathOnUSB"
|
||||
Copy-Item -Path $using:resolvedDeviceNamePrefixesPath -Destination (Join-Path $UnattendPathOnUSB 'prefixes.txt') -Force | Out-Null
|
||||
|
||||
@@ -528,6 +528,22 @@ $script:uiState.Controls.btnRun.Add_Click({
|
||||
return
|
||||
}
|
||||
}
|
||||
elseif ($config.DeviceNamingMode -eq 'SerialComputerNames') {
|
||||
if (-not $config.CopyUnattend) {
|
||||
[System.Windows.MessageBox]::Show("Select Copy Unattend.xml before using 'Specify Serial to Device Name Mapping'.", "Copy Unattend Required", "OK", "Warning") | Out-Null
|
||||
$btnRun.IsEnabled = $true
|
||||
$script:uiState.Controls.txtStatus.Text = "Build canceled: serial computer-name mapping requires Copy Unattend.xml."
|
||||
return
|
||||
}
|
||||
|
||||
$hasSavedSerialComputerNamesPath = -not [string]::IsNullOrWhiteSpace([string]$config.DeviceNameSerialComputerNamesPath) -and (Test-Path -Path $config.DeviceNameSerialComputerNamesPath -PathType Leaf)
|
||||
if ((($null -eq $config.DeviceNameSerialComputerNames) -or ($config.DeviceNameSerialComputerNames.Count -eq 0)) -and -not $hasSavedSerialComputerNamesPath) {
|
||||
[System.Windows.MessageBox]::Show("Enter CSV content or choose a valid SerialComputerNames.csv file before using 'Specify Serial to Device Name Mapping'.", "Serial Mapping Required", "OK", "Warning") | Out-Null
|
||||
$btnRun.IsEnabled = $true
|
||||
$script:uiState.Controls.txtStatus.Text = "Build canceled: serial computer-name mapping required."
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
$configFilePath = Join-Path $config.FFUDevelopmentPath "\config\FFUConfig.json"
|
||||
# Sort top-level keys alphabetically for consistent output
|
||||
|
||||
@@ -963,6 +963,24 @@
|
||||
<Button x:Name="btnSaveDeviceNamePrefixes" Content="Save Prefixes" Padding="12,4" ToolTip="Save the current prefixes list to the Prefixes File Path."/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<RadioButton x:Name="rbDeviceNamingSerialComputerNames" Content="Specify Serial to Device Name Mapping" GroupName="DeviceNamingMode" Margin="0,8,0,8" ToolTip="Create or import a SerialComputerNames.csv file. This option requires Copy Unattend.xml."/>
|
||||
<StackPanel x:Name="deviceNameSerialComputerNamesPanel" Margin="32,0,0,0" Visibility="Collapsed">
|
||||
<TextBlock Text="SerialComputerNames.csv File Path" Margin="0,0,0,8" TextWrapping="Wrap"/>
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="txtDeviceNameSerialComputerNamesPath" Grid.Column="0" VerticalAlignment="Center" ToolTip="Path to the serial-to-device-name mapping CSV file. You can use any file name."/>
|
||||
<Button x:Name="btnBrowseDeviceNameSerialComputerNamesPath" Grid.Column="1" Content="Browse..." Padding="12,4" Margin="8,0,0,0" VerticalAlignment="Center" ToolTip="Browse to a SerialComputerNames.csv source file path."/>
|
||||
</Grid>
|
||||
<TextBlock Text="Enter CSV content with SerialNumber and ComputerName headers. Each row maps one BIOS serial number to one computer name during deployment." Margin="0,0,0,4" TextWrapping="Wrap"/>
|
||||
<TextBlock Text="Example: SerialNumber,ComputerName" Margin="0,0,0,8" TextWrapping="Wrap" Opacity="0.75"/>
|
||||
<TextBox x:Name="txtDeviceNameSerialComputerNames" MinHeight="120" AcceptsReturn="True" TextWrapping="NoWrap" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" ToolTip="Each CSV row maps a serial number to a computer name."/>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8,0,0" HorizontalAlignment="Left">
|
||||
<Button x:Name="btnSaveDeviceNameSerialComputerNames" Content="Save Serial Mapping" Padding="12,4" ToolTip="Save the current serial-to-device-name mapping to the CSV file path."/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ function Get-UIConfig {
|
||||
DeviceNameTemplate = $State.Controls.txtDeviceNameTemplate.Text
|
||||
DeviceNamePrefixesPath = $State.Controls.txtDeviceNamePrefixesPath.Text
|
||||
DeviceNamePrefixes = @(Get-DeviceNamePrefixes -State $State)
|
||||
DeviceNameSerialComputerNamesPath = $State.Controls.txtDeviceNameSerialComputerNamesPath.Text
|
||||
DeviceNameSerialComputerNames = @(Get-SerialComputerNamesLines -State $State)
|
||||
CopyAdditionalFFUFiles = $State.Controls.chkCopyAdditionalFFUFiles.IsChecked
|
||||
CreateDeploymentMedia = $State.Controls.chkCreateDeploymentMedia.IsChecked
|
||||
InjectUnattend = $State.Controls.chkInjectUnattend.IsChecked
|
||||
@@ -473,21 +475,27 @@ function Update-UIFromConfig {
|
||||
Set-UIValue -ControlName 'chkCopyUnattend' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyUnattend' -State $State
|
||||
Set-UIValue -ControlName 'chkCopyPPKG' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyPPKG' -State $State
|
||||
Set-UIValue -ControlName 'txtDeviceNamePrefixesPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'DeviceNamePrefixesPath' -State $State
|
||||
Set-UIValue -ControlName 'txtDeviceNameSerialComputerNamesPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'DeviceNameSerialComputerNamesPath' -State $State
|
||||
Set-UIValue -ControlName 'txtDeviceNameTemplate' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'DeviceNameTemplate' -State $State
|
||||
Set-UIValue -ControlName 'txtDeviceNamePrefixes' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'DeviceNamePrefixes' -TransformValue { param($val) if ($val -is [System.Array]) { $val -join [System.Environment]::NewLine } else { [string]$val } } -State $State
|
||||
Set-UIValue -ControlName 'txtDeviceNameSerialComputerNames' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'DeviceNameSerialComputerNames' -TransformValue { param($val) if ($val -is [System.Array]) { $val -join [System.Environment]::NewLine } else { [string]$val } } -State $State
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($State.Controls.txtDeviceNamePrefixesPath.Text)) {
|
||||
$State.Controls.txtDeviceNamePrefixesPath.Text = Get-DefaultDeviceNamePrefixesPath -FFUDevelopmentPath $State.Controls.txtFFUDevPath.Text
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($State.Controls.txtDeviceNameSerialComputerNamesPath.Text)) {
|
||||
$State.Controls.txtDeviceNameSerialComputerNamesPath.Text = Get-DefaultSerialComputerNamesPath -FFUDevelopmentPath $State.Controls.txtFFUDevPath.Text
|
||||
}
|
||||
|
||||
$loadedDeviceNamingMode = $null
|
||||
if ($ConfigContent.PSObject.Properties.Name -contains 'DeviceNamingMode') {
|
||||
$candidateDeviceNamingMode = [string]$ConfigContent.DeviceNamingMode
|
||||
if ($candidateDeviceNamingMode -in @('Legacy', 'None', 'Prompt', 'Template', 'Prefixes')) {
|
||||
if ($candidateDeviceNamingMode -in @('Legacy', 'None', 'Prompt', 'Template', 'Prefixes', 'SerialComputerNames')) {
|
||||
$loadedDeviceNamingMode = $candidateDeviceNamingMode
|
||||
}
|
||||
}
|
||||
$displayDeviceNamingMode = if ($loadedDeviceNamingMode -in @('Prompt', 'Template', 'Prefixes')) {
|
||||
$displayDeviceNamingMode = if ($loadedDeviceNamingMode -in @('Prompt', 'Template', 'Prefixes', 'SerialComputerNames')) {
|
||||
$loadedDeviceNamingMode
|
||||
}
|
||||
else {
|
||||
@@ -495,6 +503,7 @@ function Update-UIFromConfig {
|
||||
}
|
||||
Set-DeviceNamingModeState -State $State -DisplayMode $displayDeviceNamingMode -LoadedMode $loadedDeviceNamingMode
|
||||
Import-DeviceNamePrefixesFromConfiguredPath -State $State
|
||||
Import-SerialComputerNamesFromConfiguredPath -State $State
|
||||
Update-DeviceNamingControls -State $State
|
||||
|
||||
# Post Build Cleanup group (Build Tab)
|
||||
|
||||
@@ -42,13 +42,17 @@ function Get-SelectedDeviceNamingMode {
|
||||
return 'Prefixes'
|
||||
}
|
||||
|
||||
if ($true -eq $State.Controls.rbDeviceNamingSerialComputerNames.IsChecked) {
|
||||
return 'SerialComputerNames'
|
||||
}
|
||||
|
||||
return 'None'
|
||||
}
|
||||
|
||||
function Set-DeviceNamingMode {
|
||||
param(
|
||||
[PSCustomObject]$State,
|
||||
[ValidateSet('None', 'Prompt', 'Template', 'Prefixes')]
|
||||
[ValidateSet('None', 'Prompt', 'Template', 'Prefixes', 'SerialComputerNames')]
|
||||
[string]$Mode
|
||||
)
|
||||
|
||||
@@ -56,12 +60,13 @@ function Set-DeviceNamingMode {
|
||||
$State.Controls.rbDeviceNamingPrompt.IsChecked = $Mode -eq 'Prompt'
|
||||
$State.Controls.rbDeviceNamingTemplate.IsChecked = $Mode -eq 'Template'
|
||||
$State.Controls.rbDeviceNamingPrefixes.IsChecked = $Mode -eq 'Prefixes'
|
||||
$State.Controls.rbDeviceNamingSerialComputerNames.IsChecked = $Mode -eq 'SerialComputerNames'
|
||||
}
|
||||
|
||||
function Set-DeviceNamingModeState {
|
||||
param(
|
||||
[PSCustomObject]$State,
|
||||
[ValidateSet('None', 'Prompt', 'Template', 'Prefixes')]
|
||||
[ValidateSet('None', 'Prompt', 'Template', 'Prefixes', 'SerialComputerNames')]
|
||||
[string]$DisplayMode,
|
||||
[AllowNull()]
|
||||
[string]$LoadedMode
|
||||
@@ -121,6 +126,20 @@ function Get-DeviceNamePrefixes {
|
||||
)
|
||||
}
|
||||
|
||||
function Get-SerialComputerNamesLines {
|
||||
param([PSCustomObject]$State)
|
||||
|
||||
if ($null -eq $State.Controls.txtDeviceNameSerialComputerNames) {
|
||||
return @()
|
||||
}
|
||||
|
||||
return @(
|
||||
$State.Controls.txtDeviceNameSerialComputerNames.Text -split "\r?\n" |
|
||||
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
|
||||
ForEach-Object { $_.Trim() }
|
||||
)
|
||||
}
|
||||
|
||||
function Import-DeviceNamePrefixesFile {
|
||||
param(
|
||||
[PSCustomObject]$State,
|
||||
@@ -140,6 +159,25 @@ function Import-DeviceNamePrefixesFile {
|
||||
return $true
|
||||
}
|
||||
|
||||
function Import-SerialComputerNamesFile {
|
||||
param(
|
||||
[PSCustomObject]$State,
|
||||
[string]$FilePath
|
||||
)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($FilePath) -or -not (Test-Path -Path $FilePath -PathType Leaf)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
$serialMappingLines = @(Get-Content -Path $FilePath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim() })
|
||||
if ($null -ne $State.Controls.txtDeviceNameSerialComputerNamesPath) {
|
||||
$State.Controls.txtDeviceNameSerialComputerNamesPath.Text = $FilePath
|
||||
}
|
||||
$State.Controls.txtDeviceNameSerialComputerNames.Text = $serialMappingLines -join [System.Environment]::NewLine
|
||||
WriteLog "Imported serial computer-name mappings from $FilePath"
|
||||
return $true
|
||||
}
|
||||
|
||||
function Get-DefaultDeviceNamePrefixesPath {
|
||||
param([string]$FFUDevelopmentPath)
|
||||
|
||||
@@ -150,6 +188,16 @@ function Get-DefaultDeviceNamePrefixesPath {
|
||||
return Join-Path (Join-Path $FFUDevelopmentPath 'unattend') 'prefixes.txt'
|
||||
}
|
||||
|
||||
function Get-DefaultSerialComputerNamesPath {
|
||||
param([string]$FFUDevelopmentPath)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($FFUDevelopmentPath)) {
|
||||
return $null
|
||||
}
|
||||
|
||||
return Join-Path (Join-Path $FFUDevelopmentPath 'unattend') 'SerialComputerNames.csv'
|
||||
}
|
||||
|
||||
function Get-DefaultUnattendFilePath {
|
||||
param(
|
||||
[string]$FFUDevelopmentPath,
|
||||
@@ -188,6 +236,29 @@ function Import-DeviceNamePrefixesFromConfiguredPath {
|
||||
}
|
||||
}
|
||||
|
||||
function Import-SerialComputerNamesFromConfiguredPath {
|
||||
param(
|
||||
[PSCustomObject]$State,
|
||||
[switch]$SkipIfTextPresent
|
||||
)
|
||||
|
||||
if ($SkipIfTextPresent -and -not [string]::IsNullOrWhiteSpace($State.Controls.txtDeviceNameSerialComputerNames.Text)) {
|
||||
return
|
||||
}
|
||||
|
||||
$serialComputerNamesPath = $State.Controls.txtDeviceNameSerialComputerNamesPath.Text
|
||||
if ([string]::IsNullOrWhiteSpace($serialComputerNamesPath)) {
|
||||
$serialComputerNamesPath = Get-DefaultSerialComputerNamesPath -FFUDevelopmentPath $State.Controls.txtFFUDevPath.Text
|
||||
if (-not [string]::IsNullOrWhiteSpace($serialComputerNamesPath) -and $null -ne $State.Controls.txtDeviceNameSerialComputerNamesPath) {
|
||||
$State.Controls.txtDeviceNameSerialComputerNamesPath.Text = $serialComputerNamesPath
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-Path -Path $serialComputerNamesPath -PathType Leaf) {
|
||||
Import-SerialComputerNamesFile -State $State -FilePath $serialComputerNamesPath | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Test-DeviceNameTemplateUsesSerialToken {
|
||||
param([PSCustomObject]$State)
|
||||
|
||||
@@ -201,7 +272,7 @@ function Update-UnattendSelectionControls {
|
||||
$isCopyUnattendSelected = $true -eq $State.Controls.chkCopyUnattend.IsChecked
|
||||
$isInjectUnattendSelected = $true -eq $State.Controls.chkInjectUnattend.IsChecked
|
||||
$deviceNameTemplateUsesSerialToken = Test-DeviceNameTemplateUsesSerialToken -State $State
|
||||
$requiresCopiedUnattend = ($selectedDeviceNamingMode -in @('Prompt', 'Prefixes')) -or $deviceNameTemplateUsesSerialToken
|
||||
$requiresCopiedUnattend = ($selectedDeviceNamingMode -in @('Prompt', 'Prefixes', 'SerialComputerNames')) -or $deviceNameTemplateUsesSerialToken
|
||||
|
||||
if ($isCopyUnattendSelected -and $isInjectUnattendSelected) {
|
||||
if ($requiresCopiedUnattend) {
|
||||
@@ -247,19 +318,24 @@ function Update-UnattendSelectionControls {
|
||||
function Update-DeviceNamingControls {
|
||||
param([PSCustomObject]$State)
|
||||
|
||||
if (($true -eq $State.Controls.chkInjectUnattend.IsChecked) -and (($true -eq $State.Controls.rbDeviceNamingPrompt.IsChecked) -or ($true -eq $State.Controls.rbDeviceNamingPrefixes.IsChecked))) {
|
||||
if (($true -eq $State.Controls.chkInjectUnattend.IsChecked) -and (($true -eq $State.Controls.rbDeviceNamingPrompt.IsChecked) -or ($true -eq $State.Controls.rbDeviceNamingPrefixes.IsChecked) -or ($true -eq $State.Controls.rbDeviceNamingSerialComputerNames.IsChecked))) {
|
||||
$State.Controls.rbDeviceNamingNone.IsChecked = $true
|
||||
}
|
||||
|
||||
$selectedDeviceNamingMode = Get-SelectedDeviceNamingMode -State $State
|
||||
$State.Controls.deviceNameTemplatePanel.Visibility = if ($selectedDeviceNamingMode -eq 'Template') { 'Visible' } else { 'Collapsed' }
|
||||
$State.Controls.deviceNamePrefixesPanel.Visibility = if ($selectedDeviceNamingMode -eq 'Prefixes') { 'Visible' } else { 'Collapsed' }
|
||||
$State.Controls.deviceNameSerialComputerNamesPanel.Visibility = if ($selectedDeviceNamingMode -eq 'SerialComputerNames') { 'Visible' } else { 'Collapsed' }
|
||||
$State.Controls.rbDeviceNamingPrompt.IsEnabled = -not ($true -eq $State.Controls.chkInjectUnattend.IsChecked)
|
||||
$State.Controls.rbDeviceNamingPrefixes.IsEnabled = -not ($true -eq $State.Controls.chkInjectUnattend.IsChecked)
|
||||
$State.Controls.rbDeviceNamingSerialComputerNames.IsEnabled = -not ($true -eq $State.Controls.chkInjectUnattend.IsChecked)
|
||||
|
||||
if ($selectedDeviceNamingMode -eq 'Prefixes') {
|
||||
Import-DeviceNamePrefixesFromConfiguredPath -State $State -SkipIfTextPresent
|
||||
}
|
||||
elseif ($selectedDeviceNamingMode -eq 'SerialComputerNames') {
|
||||
Import-SerialComputerNamesFromConfiguredPath -State $State -SkipIfTextPresent
|
||||
}
|
||||
|
||||
Update-UnattendSelectionControls -State $State
|
||||
}
|
||||
@@ -480,18 +556,24 @@ function Register-EventHandlers {
|
||||
$selectedPath = Invoke-BrowseAction -Type 'Folder' -Title "Select FFU Development Path"
|
||||
if ($selectedPath) {
|
||||
$currentPrefixesPath = $localState.Controls.txtDeviceNamePrefixesPath.Text
|
||||
$currentSerialComputerNamesPath = $localState.Controls.txtDeviceNameSerialComputerNamesPath.Text
|
||||
$currentUnattendX64FilePath = $localState.Controls.txtUnattendX64FilePath.Text
|
||||
$currentUnattendArm64FilePath = $localState.Controls.txtUnattendArm64FilePath.Text
|
||||
$previousDefaultPrefixesPath = Get-DefaultDeviceNamePrefixesPath -FFUDevelopmentPath $localState.Controls.txtFFUDevPath.Text
|
||||
$previousDefaultSerialComputerNamesPath = Get-DefaultSerialComputerNamesPath -FFUDevelopmentPath $localState.Controls.txtFFUDevPath.Text
|
||||
$previousDefaultUnattendX64FilePath = Get-DefaultUnattendFilePath -FFUDevelopmentPath $localState.Controls.txtFFUDevPath.Text -WindowsArch 'x64'
|
||||
$previousDefaultUnattendArm64FilePath = Get-DefaultUnattendFilePath -FFUDevelopmentPath $localState.Controls.txtFFUDevPath.Text -WindowsArch 'arm64'
|
||||
$localState.Controls.txtFFUDevPath.Text = $selectedPath
|
||||
$newDefaultPrefixesPath = Get-DefaultDeviceNamePrefixesPath -FFUDevelopmentPath $selectedPath
|
||||
$newDefaultSerialComputerNamesPath = Get-DefaultSerialComputerNamesPath -FFUDevelopmentPath $selectedPath
|
||||
$newDefaultUnattendX64FilePath = Get-DefaultUnattendFilePath -FFUDevelopmentPath $selectedPath -WindowsArch 'x64'
|
||||
$newDefaultUnattendArm64FilePath = Get-DefaultUnattendFilePath -FFUDevelopmentPath $selectedPath -WindowsArch 'arm64'
|
||||
if ([string]::IsNullOrWhiteSpace($currentPrefixesPath) -or $currentPrefixesPath -ieq $previousDefaultPrefixesPath) {
|
||||
$localState.Controls.txtDeviceNamePrefixesPath.Text = $newDefaultPrefixesPath
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($currentSerialComputerNamesPath) -or $currentSerialComputerNamesPath -ieq $previousDefaultSerialComputerNamesPath) {
|
||||
$localState.Controls.txtDeviceNameSerialComputerNamesPath.Text = $newDefaultSerialComputerNamesPath
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($currentUnattendX64FilePath) -or $currentUnattendX64FilePath -ieq $previousDefaultUnattendX64FilePath) {
|
||||
$localState.Controls.txtUnattendX64FilePath.Text = $newDefaultUnattendX64FilePath
|
||||
}
|
||||
@@ -499,6 +581,7 @@ function Register-EventHandlers {
|
||||
$localState.Controls.txtUnattendArm64FilePath.Text = $newDefaultUnattendArm64FilePath
|
||||
}
|
||||
Import-DeviceNamePrefixesFromConfiguredPath -State $localState
|
||||
Import-SerialComputerNamesFromConfiguredPath -State $localState
|
||||
Update-DeviceNamingControls -State $localState
|
||||
}
|
||||
})
|
||||
@@ -560,6 +643,16 @@ function Register-EventHandlers {
|
||||
}
|
||||
Update-DeviceNamingControls -State $localState
|
||||
})
|
||||
$State.Controls.rbDeviceNamingSerialComputerNames.Add_Checked({
|
||||
param($eventSource, $routedEventArgs)
|
||||
$window = [System.Windows.Window]::GetWindow($eventSource)
|
||||
$localState = $window.Tag
|
||||
if (-not ($true -eq $localState.Flags.suppressDeviceNamingChangeTracking)) {
|
||||
$localState.Flags.deviceNamingModeWasExplicitlyChanged = $true
|
||||
$localState.Data.loadedDeviceNamingMode = $null
|
||||
}
|
||||
Update-DeviceNamingControls -State $localState
|
||||
})
|
||||
$State.Controls.btnBrowseDeviceNamePrefixesPath.Add_Click({
|
||||
param($eventSource, $routedEventArgs)
|
||||
$window = [System.Windows.Window]::GetWindow($eventSource)
|
||||
@@ -580,6 +673,26 @@ function Register-EventHandlers {
|
||||
Update-DeviceNamingControls -State $localState
|
||||
}
|
||||
})
|
||||
$State.Controls.btnBrowseDeviceNameSerialComputerNamesPath.Add_Click({
|
||||
param($eventSource, $routedEventArgs)
|
||||
$window = [System.Windows.Window]::GetWindow($eventSource)
|
||||
$localState = $window.Tag
|
||||
$currentSerialComputerNamesPath = $localState.Controls.txtDeviceNameSerialComputerNamesPath.Text
|
||||
if ([string]::IsNullOrWhiteSpace($currentSerialComputerNamesPath)) {
|
||||
$currentSerialComputerNamesPath = Get-DefaultSerialComputerNamesPath -FFUDevelopmentPath $localState.Controls.txtFFUDevPath.Text
|
||||
}
|
||||
$initialDirectory = if ([string]::IsNullOrWhiteSpace($currentSerialComputerNamesPath)) {
|
||||
$null
|
||||
}
|
||||
else {
|
||||
Split-Path $currentSerialComputerNamesPath -Parent
|
||||
}
|
||||
$fileName = if ([string]::IsNullOrWhiteSpace($currentSerialComputerNamesPath)) { 'SerialComputerNames.csv' } else { Split-Path $currentSerialComputerNamesPath -Leaf }
|
||||
$selectedPath = Invoke-BrowseAction -Type 'OpenFile' -Title 'Select SerialComputerNames.csv file path' -Filter 'CSV files (*.csv)|*.csv|All files (*.*)|*.*' -InitialDirectory $initialDirectory -FileName $fileName
|
||||
if (Import-SerialComputerNamesFile -State $localState -FilePath $selectedPath) {
|
||||
Update-DeviceNamingControls -State $localState
|
||||
}
|
||||
})
|
||||
$State.Controls.btnBrowseUnattendX64FilePath.Add_Click({
|
||||
param($eventSource, $routedEventArgs)
|
||||
$window = [System.Windows.Window]::GetWindow($eventSource)
|
||||
@@ -653,6 +766,39 @@ function Register-EventHandlers {
|
||||
[System.Windows.MessageBox]::Show("Saving prefixes failed for '$currentPrefixesPath'. $($_.Exception.Message)", "Save Prefixes Failed", "OK", "Error") | Out-Null
|
||||
}
|
||||
})
|
||||
$State.Controls.btnSaveDeviceNameSerialComputerNames.Add_Click({
|
||||
param($eventSource, $routedEventArgs)
|
||||
$window = [System.Windows.Window]::GetWindow($eventSource)
|
||||
$localState = $window.Tag
|
||||
$serialComputerNameLines = @(Get-SerialComputerNamesLines -State $localState)
|
||||
|
||||
if ($serialComputerNameLines.Count -eq 0) {
|
||||
[System.Windows.MessageBox]::Show("Enter CSV content before saving the serial mapping file.", "Serial Mapping Required", "OK", "Warning") | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
$currentSerialComputerNamesPath = $localState.Controls.txtDeviceNameSerialComputerNamesPath.Text
|
||||
if ([string]::IsNullOrWhiteSpace($currentSerialComputerNamesPath)) {
|
||||
$currentSerialComputerNamesPath = Get-DefaultSerialComputerNamesPath -FFUDevelopmentPath $localState.Controls.txtFFUDevPath.Text
|
||||
if (-not [string]::IsNullOrWhiteSpace($currentSerialComputerNamesPath)) {
|
||||
$localState.Controls.txtDeviceNameSerialComputerNamesPath.Text = $currentSerialComputerNamesPath
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($currentSerialComputerNamesPath)) {
|
||||
[System.Windows.MessageBox]::Show("Select a valid SerialComputerNames.csv file path before saving the serial mapping.", "Serial Mapping File Path Required", "OK", "Warning") | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$serialComputerNameLines | Set-Content -Path $currentSerialComputerNamesPath -Encoding UTF8
|
||||
$localState.Controls.txtDeviceNameSerialComputerNamesPath.Text = $currentSerialComputerNamesPath
|
||||
WriteLog "Saved serial computer-name mappings to $currentSerialComputerNamesPath"
|
||||
}
|
||||
catch {
|
||||
[System.Windows.MessageBox]::Show("Saving serial mapping failed for '$currentSerialComputerNamesPath'. $($_.Exception.Message)", "Save Serial Mapping Failed", "OK", "Error") | Out-Null
|
||||
}
|
||||
})
|
||||
$State.Controls.chkCopyUnattend.Add_Checked({
|
||||
param($eventSource, $routedEventArgs)
|
||||
$window = [System.Windows.Window]::GetWindow($eventSource)
|
||||
|
||||
@@ -228,13 +228,19 @@ function Initialize-UIControls {
|
||||
$State.Controls.rbDeviceNamingPrompt = $window.FindName('rbDeviceNamingPrompt')
|
||||
$State.Controls.rbDeviceNamingTemplate = $window.FindName('rbDeviceNamingTemplate')
|
||||
$State.Controls.rbDeviceNamingPrefixes = $window.FindName('rbDeviceNamingPrefixes')
|
||||
$State.Controls.rbDeviceNamingSerialComputerNames = $window.FindName('rbDeviceNamingSerialComputerNames')
|
||||
$State.Controls.deviceNameTemplatePanel = $window.FindName('deviceNameTemplatePanel')
|
||||
$State.Controls.deviceNamePrefixesPanel = $window.FindName('deviceNamePrefixesPanel')
|
||||
$State.Controls.deviceNameSerialComputerNamesPanel = $window.FindName('deviceNameSerialComputerNamesPanel')
|
||||
$State.Controls.txtDeviceNameTemplate = $window.FindName('txtDeviceNameTemplate')
|
||||
$State.Controls.txtDeviceNamePrefixesPath = $window.FindName('txtDeviceNamePrefixesPath')
|
||||
$State.Controls.btnBrowseDeviceNamePrefixesPath = $window.FindName('btnBrowseDeviceNamePrefixesPath')
|
||||
$State.Controls.txtDeviceNamePrefixes = $window.FindName('txtDeviceNamePrefixes')
|
||||
$State.Controls.btnSaveDeviceNamePrefixes = $window.FindName('btnSaveDeviceNamePrefixes')
|
||||
$State.Controls.txtDeviceNameSerialComputerNamesPath = $window.FindName('txtDeviceNameSerialComputerNamesPath')
|
||||
$State.Controls.btnBrowseDeviceNameSerialComputerNamesPath = $window.FindName('btnBrowseDeviceNameSerialComputerNamesPath')
|
||||
$State.Controls.txtDeviceNameSerialComputerNames = $window.FindName('txtDeviceNameSerialComputerNames')
|
||||
$State.Controls.btnSaveDeviceNameSerialComputerNames = $window.FindName('btnSaveDeviceNameSerialComputerNames')
|
||||
$State.Controls.chkVerbose = $window.FindName('chkVerbose')
|
||||
$State.Controls.chkCopyAutopilot = $window.FindName('chkCopyAutopilot')
|
||||
$State.Controls.chkCopyUnattend = $window.FindName('chkCopyUnattend')
|
||||
@@ -400,7 +406,7 @@ function Initialize-UIDefaults {
|
||||
$State.Controls.chkCopyAutopilot.IsChecked = $State.Defaults.generalDefaults.CopyAutopilot
|
||||
$State.Controls.chkCopyUnattend.IsChecked = $State.Defaults.generalDefaults.CopyUnattend
|
||||
$State.Controls.chkCopyPPKG.IsChecked = $State.Defaults.generalDefaults.CopyPPKG
|
||||
$defaultDeviceNamingMode = if ($State.Defaults.generalDefaults.DeviceNamingMode -in @('None', 'Prompt', 'Template', 'Prefixes')) {
|
||||
$defaultDeviceNamingMode = if ($State.Defaults.generalDefaults.DeviceNamingMode -in @('None', 'Prompt', 'Template', 'Prefixes', 'SerialComputerNames')) {
|
||||
$State.Defaults.generalDefaults.DeviceNamingMode
|
||||
}
|
||||
else {
|
||||
@@ -410,7 +416,10 @@ function Initialize-UIDefaults {
|
||||
$State.Controls.txtDeviceNameTemplate.Text = $State.Defaults.generalDefaults.DeviceNameTemplate
|
||||
$State.Controls.txtDeviceNamePrefixesPath.Text = $State.Defaults.generalDefaults.DeviceNamePrefixesPath
|
||||
$State.Controls.txtDeviceNamePrefixes.Text = ($State.Defaults.generalDefaults.DeviceNamePrefixes -join [System.Environment]::NewLine)
|
||||
$State.Controls.txtDeviceNameSerialComputerNamesPath.Text = $State.Defaults.generalDefaults.DeviceNameSerialComputerNamesPath
|
||||
$State.Controls.txtDeviceNameSerialComputerNames.Text = ($State.Defaults.generalDefaults.DeviceNameSerialComputerNames -join [System.Environment]::NewLine)
|
||||
Import-DeviceNamePrefixesFromConfiguredPath -State $State
|
||||
Import-SerialComputerNamesFromConfiguredPath -State $State
|
||||
Update-DeviceNamingControls -State $State
|
||||
$State.Controls.chkCleanupAppsISO.IsChecked = $State.Defaults.generalDefaults.CleanupAppsISO
|
||||
$State.Controls.chkCleanupDeployISO.IsChecked = $State.Defaults.generalDefaults.CleanupDeployISO
|
||||
|
||||
@@ -112,6 +112,7 @@ function Get-GeneralDefaults {
|
||||
$userAppListPath = Join-Path -Path $appsPath -ChildPath "UserAppList.json"
|
||||
$driversJsonPath = Join-Path -Path $driversPath -ChildPath "Drivers.json"
|
||||
$deviceNamePrefixesPath = Join-Path -Path $unattendPath -ChildPath "prefixes.txt"
|
||||
$deviceNameSerialComputerNamesPath = Join-Path -Path $unattendPath -ChildPath "SerialComputerNames.csv"
|
||||
$unattendX64FilePath = Join-Path -Path $unattendPath -ChildPath "unattend_x64.xml"
|
||||
$unattendArm64FilePath = Join-Path -Path $unattendPath -ChildPath "unattend_arm64.xml"
|
||||
|
||||
@@ -142,6 +143,8 @@ function Get-GeneralDefaults {
|
||||
DeviceNameTemplate = ''
|
||||
DeviceNamePrefixesPath = $deviceNamePrefixesPath
|
||||
DeviceNamePrefixes = @()
|
||||
DeviceNameSerialComputerNamesPath = $deviceNameSerialComputerNamesPath
|
||||
DeviceNameSerialComputerNames = @()
|
||||
CleanupAppsISO = $true
|
||||
CleanupDeployISO = $true
|
||||
CleanupDrivers = $false
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
SerialNumber,ComputerName
|
||||
ABC12345,CORP-001
|
||||
DEF67890,KIOSK-010
|
||||
XYZ24680,STORE-015
|
||||
|
Reference in New Issue
Block a user