Public/Add-HDTBootImageComponent.ps1
|
function Add-HDTBootImageComponent { <# .SYNOPSIS Declares a WinPE optional component for the boot image, leaving every other line of workspace.yaml byte-identical. .DESCRIPTION The command an administrator types to add a WinPE optional component, and the one anything with an Add Component button has to run. RUN Get-HDTAdkComponent FIRST to see what this build host can offer, what each cab costs and what it depends on. This command checks the NAME's shape; whether a cab of that name exists is settled against the ADK, by Get-HDTAdkComponent now or by the build later. ADDING NEVER REMOVES. An absent optionalComponents key does not mean "no components": it means the administrator did not say, and the engine applies WinPE-SecureStartup, WinPE-EnhancedStorage and WinPE-WDS-Tools. Writing only the new name would delete those three from the image, which is the last thing anybody typing Add expects - so the first add to an unstated list writes the defaults out with it. The defaults come from the engine's own reader rather than from a copy kept here, so there is one place they can change. THE REQUIRED SIX ARE NOT WRITTEN AND CANNOT BE ADDED. WinPE-WMI, WinPE-NetFx, WinPE-Scripting, WinPE-PowerShell, WinPE-StorageWMI and WinPE-DismCmdlets are applied to every HDT boot image, first, in an order a machine that booted verified. They are not configuration, and a document that listed them would be a document that could disagree with the engine. IT SPLICES LINES AND NEVER PARSES AND RE-EMITS, so the trailing comment somebody wrote beside an existing component - `- WinPE-SecureStartup # BitLocker` - is still there afterwards. IT RETURNS LINES AND WRITES NOTHING. Save-HDTWorkspaceDocument is what touches the share. .PARAMETER Line The document, already split into lines. .PARAMETER Name The components to add, in the order they should be written. A component is named as the ADK names its cab - WinPE-WMI, WinPE-NetFx; note the lowercase x. .INPUTS None. This command does not accept pipeline input. .OUTPUTS System.String[] - the document with the components added. .EXAMPLE Add-HDTBootImageComponent -Line $line -Name 'WinPE-HTA' .EXAMPLE Add-HDTBootImageComponent -Line $line -Name @('WinPE-Setup', 'WinPE-Setup-Client') A component and the one it depends on, in one edit. .LINK Get-HDTAdkComponent .LINK Get-HDTBootImageComponent #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] [OutputType([string[]])] param( [Parameter(Mandatory = $true, Position = 0)] [AllowEmptyCollection()] [AllowEmptyString()] [string[]] $Line, [Parameter(Mandatory = $true, Position = 1)] [ValidateNotNullOrEmpty()] [string[]] $Name ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $workspace = ConvertFrom-HDTWorkspaceLine -Line $Line $declared = New-Object -TypeName System.Collections.ArrayList foreach ($current in @($workspace.BootImage.OptionalComponent)) { [void] $declared.Add(([string] $current).ToLowerInvariant()) } foreach ($current in @($Name)) { if ($current -notmatch '^WinPE-[A-Za-z0-9-]+$') { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $current ` -Message ("'{0}' is not a WinPE optional component name. A component is named as the ADK names its cab, for example WinPE-WMI or WinPE-NetFx - note the lowercase x. Run Get-HDTAdkComponent for the ones this build host can offer." -f $current))) } $comparable = $current.ToLowerInvariant() if ($declared -contains $comparable) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $current ` -Message ("'{0}' is already in this boot image. Component names are compared without regard to case, and applying a cab twice is not a thing to ask for by accident." -f $current))) } [void] $declared.Add($comparable) } if (-not $PSCmdlet.ShouldProcess((@($Name) -join ', '), 'Add to the boot image components')) { return [string[]] @($Line) } $block = Get-HDTWorkspaceKey -Line $Line -Path @('bootImage', 'optionalComponents') $result = [string[]] @($Line) if ($null -ne $block) { # ONE ENTRY PER LINE, APPENDED. Rewriting the list would lose whatever # was written beside the components already in it. foreach ($current in @($Name)) { $block = Get-HDTWorkspaceKey -Line $result -Path @('bootImage', 'optionalComponents') $result = [string[]] @(Add-HDTWorkspaceItem -Line $result -Block $block ` -Text ([string[]] @('- {0}' -f (ConvertTo-HDTRuleScalarText -Value $current)))) } } else { # THE UNSTATED DEFAULTS ARE WRITTEN OUT WITH THE NEW ONE, so an add adds. $written = New-Object -TypeName System.Collections.ArrayList [void] $written.Add('optionalComponents:') foreach ($current in @(@($workspace.BootImage.OptionalComponent) + @($Name))) { [void] $written.Add(' - {0}' -f (ConvertTo-HDTRuleScalarText -Value ([string] $current))) } $result = [string[]] @(Set-HDTWorkspaceKey -Line $result -Path @('bootImage', 'optionalComponents') ` -Text ([string[]] @($written))) } try { [void] (ConvertFrom-HDTWorkspaceLine -Line $result) } catch { $PSCmdlet.ThrowTerminatingError($_) } return [string[]] $result } |