Public/Get-HDTWizardField.ps1
|
function Get-HDTWizardField { <# .SYNOPSIS Works out what every box on the Welcome screen should say, without a window. .DESCRIPTION W2 of the WPF-first direction, and the reason it is a command rather than code inside the window host. NEW-HDTWIZARDHOST'S TDD EXEMPTION IS CONDITIONAL. HDT exempts a thin adapter over an external tool - here WPF itself - and the price of that exemption is that the adapter must stay BRANCH-FREE, "because it is not unit tested". The host had stopped paying it: it read the network, decided which named boxes were present, decided what belonged in each, and swallowed every failure. The first time it was ever really executed, it crashed. That is the exemption being charged in the one place nobody can see it - on a bench, in WinPE, with a technician watching. So the decisions are here, where Pester can reach them with no display and no boot image, and the host is plumbing again: load the markup, apply this list by name, wire the buttons, show it. That is also what WPF-FIRST asked for in the first place - "the command holds the logic and is callable without the window". A FIELD IS A CONTROL NAME AND THE TEXT THAT GOES IN IT, nothing more. The host does not interpret them; it calls FindName and sets Text. A field naming a control the window does not have is a box that silently stays empty in WinPE, so the names are asserted against the shipped XAML in tests/unit/Get-HDTWizardField.Tests.ps1. THE PASSWORD IS NEVER A FIELD, and that is a rule rather than an omission. bootstrap.json can carry a credential and this command can see it; a prefilled PasswordBox would put the share password on a screen in a room where somebody is deploying a machine. MDT never prefills it either. BLANK DOMAIN MEANS LOCAL, so a domain that IS the server is shown as blank. Get-HDTWizardCredential composes the two back into SERVER\user, so the round trip is identical either way - but the page's own hint says "leave blank if the account is local to the server", and prefilling the server name there teaches the technician the opposite of what the hint says. NOTHING HERE IS A PRECONDITION. A machine whose network read failed, an image with no embedded credential, a boot with no bootstrap document at all - each simply produces fewer fields. The Welcome screen must open on the machine that is having the problem. .PARAMETER NetworkConfiguration What Get-HDTNetworkConfiguration returned. Omitted, the address boxes are left alone. .PARAMETER Bootstrap What Get-HDTBootstrapConfiguration returned. Omitted, the share and account boxes are left alone. .INPUTS None. This command does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject[] with Name and Text. .EXAMPLE Get-HDTWizardField -NetworkConfiguration (Get-HDTNetworkConfiguration) The address boxes, filled from the lease the machine actually got. .EXAMPLE $field = Get-HDTWizardField -NetworkConfiguration $network -Bootstrap $bootstrap foreach ($current in $field) { $window.FindName($current.Name).Text = $current.Text } What the host does with the result, and all it does with it. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter()] [AllowNull()] [object] $NetworkConfiguration, [Parameter()] [AllowNull()] [object] $Bootstrap ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $field = @() # A property read that tolerates an object which simply does not have it. # These come from two different readers and from a boot that may have # neither, so "the machine did not tell us" is an ordinary answer here. $textOf = { param([object] $Source, [string] $Name) if ($null -eq $Source) { return '' } if ($null -eq $Source.PSObject.Properties[$Name]) { return '' } return [string] $Source.$Name } # NAME, VALUE, AND WHICH PROPERTY IT GOES IN. Text for a TextBox and # Password for a PasswordBox - the same pair wizard.yaml's collect # declarations use, and the same pair Get-HDTWizardHarvest reads back with. # A host that worked the property out from the control's type would be # deciding something, which is what an untested adapter may not do. $add = { param([string] $Name, [string] $Text, [string] $Property = 'Text') return [pscustomobject] @{ Name = $Name Text = $Text Property = $Property } } # -- 1. the lease, shown rather than guessed ---------------------------- if ($null -ne $NetworkConfiguration) { $field += & $add 'HDTIpAddressBox' (& $textOf $NetworkConfiguration 'IPAddress') $field += & $add 'HDTSubnetMaskBox' (& $textOf $NetworkConfiguration 'SubnetMask') $field += & $add 'HDTGatewayBox' (& $textOf $NetworkConfiguration 'Gateway') $field += & $add 'HDTDnsBox' (& $textOf $NetworkConfiguration 'DnsServerText') } # -- 2. what the image it booted already knows -------------------------- if ($null -ne $Bootstrap) { $deployRoot = & $textOf $Bootstrap 'DeployRoot' $field += & $add 'HDTDeployRootBox' $deployRoot $userName = & $textOf $Bootstrap 'UserName' $userId = $userName $userDomain = '' if ($userName.Contains('\')) { $part = @($userName.Split('\')) $userDomain = [string] $part[0] $userId = [string] $part[$part.Count - 1] } # BLANK MEANS LOCAL. See the header: the domain box shows a domain only # when it is not simply the server the share lives on. $server = '' if ($deployRoot.StartsWith('\\')) { $segment = @($deployRoot.TrimStart('\').Split('\') | Where-Object { $_ }) if ($segment.Count -ge 1) { $server = [string] $segment[0] } } if ($userDomain -eq $server) { $userDomain = '' } $field += & $add 'HDTUserIdBox' $userId $field += & $add 'HDTUserDomainBox' $userDomain } # -- 3. the password, which IS prefilled ------------------------------- # # AN EARLIER VERSION REFUSED TO, and the reasoning was that a prefilled # PasswordBox puts the share password on a screen in a room where somebody # is deploying a machine. Two facts overturned it: # # IT IS ALREADY IN THE IMAGE. bootstrap.json inside the boot media # carries this credential; anybody holding the media has the password # already, which is exactly why DESIGN 6.3 says to treat boot media as a # credential. Withholding it from the screen protects nothing. # # A PasswordBox SHOWS DOTS. It is masked unless the technician presses the # eye - so it is not on screen in any readable sense until somebody # deliberately asks for it. # # AND THE SCREEN IS SHOWN WHEN THE SHARE CANNOT BE REACHED, which is # precisely the moment a technician needs to try the same account against # a corrected UNC. Making them retype a password they cannot see written # down anywhere is how that attempt fails for a second, unrelated reason. if ($null -ne $Bootstrap -and $null -ne $Bootstrap.PSObject.Members['GetCredential']) { $secret = '' try { $credential = $Bootstrap.GetCredential() if ($null -ne $credential) { $secret = [string] $credential.GetNetworkCredential().Password } } catch { # An image built with no embedded credential answers nothing here, # and that is an ordinary boot rather than a failure. $secret = '' } if (-not [string]::IsNullOrEmpty($secret)) { $field += & $add 'HDTPasswordBox' $secret 'Password' } } return $field } |