Public/New-HDTBootImageUnattend.ps1
|
function New-HDTBootImageUnattend { <# .SYNOPSIS Puts this module's WinPE answer file template on the share. .DESCRIPTION THE OTHER HALF OF Set-HDTBootImageUnattend. That command names a file in workspace.yaml and deliberately does not check whether it exists - a document is not a filesystem. This one makes the file exist, and it makes it exist with something in it. WHAT IT WRITES IS Templates\unattend-winpe.xml, the document this module ships: a windowsPE pass setting the display to 1024x768, which is what the deployment wizard was laid out for and larger than the 800x600 WinPE falls back to. It launches nothing - startnet.cmd already starts the engine, and a RunSynchronous here would start a second one against the same share and the same log. IT IS A COPY, NOT A LINK. The file is the administrator's from the moment it lands: wpeinit also reads EnableFirewall, EnableNetwork, LogPath, PageFile and Restart, and setting any of them means editing this file. Upgrading the module does not change a share's copy, and that is the point. IT RETURNS Relative AS WELL AS Path because workspace.yaml wants the relative one. A rooted path is legal there - Update-HDTBootImage resolves both - but a file that lives on the share written as C:\HDTLab\Share\Unattend-PE.xml names one build host's drive letter in a document every build host reads. IT REFUSES AN EXISTING FILE. Somebody's answer file, with their firewall setting in it, is not this command's to replace on the way past; -Force is how that is said out loud. .PARAMETER Workspace The deployment share's root. .PARAMETER Path Where on the share to write it, relative to the root. Defaults to Unattend-PE.xml, which is what MDT's boot image answer file is called minus MDT's architecture suffix. .PARAMETER Force Overwrite an answer file that is already there. .PARAMETER FileSystem An IFileSystem. Defaults to the real one. .INPUTS None. This command does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject with Path and Relative. .EXAMPLE New-HDTBootImageUnattend -Workspace C:\HDTLab\Share .EXAMPLE $made = New-HDTBootImageUnattend -Workspace C:\HDTLab\Share $line = Set-HDTBootImageUnattend -Line $line -Path $made.Relative The two halves: the file exists, and the document names it. #> [CmdletBinding(SupportsShouldProcess = $true)] [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Workspace, [Parameter(Position = 1)] [ValidateNotNullOrEmpty()] [string] $Path = 'Unattend-PE.xml', [Parameter()] [switch] $Force, [Parameter()] [AllowNull()] [object] $FileSystem ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' if ($null -eq $FileSystem) { $FileSystem = New-HDTFileSystem } # ON THE SHARE, WHICH IS WHAT MAKES Relative MEAN ANYTHING. A rooted path # here would write outside the workspace and hand back a Relative naming # nothing. if ([System.IO.Path]::IsPathRooted($Path)) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $Path ` -Message ("'{0}' is a rooted path. This writes the answer file onto the share, so the name is relative to it - Unattend-PE.xml, or Config\WinPE.xml. To name a file you keep elsewhere, use Set-HDTBootImageUnattend on its own." -f $Path))) } $target = [System.IO.Path]::Combine($Workspace, $Path) if ($FileSystem.TestPath($target) -and -not $Force) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $target -Category ResourceExists ` -Message ("there is already an answer file at '{0}'. It may be the one somebody set the WinPE firewall in; pass -Force to replace it." -f $target))) } # THE MODULE'S OWN COPY IS READ WITH THE MODULE'S OWN FILESYSTEM, not with # the injected one: the injected one describes the share, and under a fake # it describes a share that has no module in it. $source = Join-Path -Path (Join-Path -Path $script:HDTModuleRoot -ChildPath 'Templates') ` -ChildPath 'unattend-winpe.xml' $moduleFileSystem = New-HDTFileSystem if (-not $moduleFileSystem.TestPath($source)) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $source -Category ObjectNotFound ` -Message ("this module ships a WinPE answer file template and it is not at '{0}'. The install is incomplete." -f $source))) } if (-not $PSCmdlet.ShouldProcess($target, 'Write the WinPE answer file template')) { return [pscustomobject] @{ Path = [string] $target Relative = [string] $Path } } $folder = [System.IO.Path]::GetDirectoryName($target) if (-not [string]::IsNullOrWhiteSpace($folder) -and -not $FileSystem.TestPath($folder)) { [void] $FileSystem.CreateDirectory($folder) } $FileSystem.WriteAllText($target, [string] $moduleFileSystem.ReadAllText($source)) return [pscustomobject] @{ Path = [string] $target Relative = [string] $Path } } |