Public/Steps/Invoke-HDTSetVariableStep.ps1
|
function Invoke-HDTSetVariableStep { <# .SYNOPSIS Assigns deployment variables from inside a sequence. .DESCRIPTION The imperative counterpart to rules.yaml. Where a rule says "this is true of this machine", a SetVariable step says "this is true from here on": - name: Enter the install stage type: SetVariable variables: HDTStage: install HDTComputerName: PC-%HDTSerialNumber% or, for a single assignment, `variable:` and `value:`. Values are expanded with Expand-HDTVariableToken against the LIVE dictionary, in document order, so a later key in the same step can reference an earlier one. An unresolved token is left LITERAL and reported (02-03's rule): a token that silently became '' is how a machine ends up named 'PC-'. IT OVERWRITES, AND THAT IS THE POINT. Add-HDTResolvedVariable refuses to - first writer wins, because rule precedence is a precedence order rather than a race. This is the opposite case, so it writes $Context.Variable directly and does NOT join 02-03's closed provenance Source set. Its provenance is the var.resolve record on the JSONL stream, carrying data.source = 'Step' and the step name, which is what a technician reading the log actually needs. The record is written at Info rather than Debug, unlike a rule resolution: an authored mid-sequence assignment is a decision somebody made, not a derivation. IT REFUSES an _HDT* name, which is engine-owned and read-only, and a name outside ^HDT[A-Za-z0-9_]*$ - both as terminating configuration errors, because a sequence that assigns the wrong namespace is broken authoring rather than a failed operation. A step with no assignment at all is a FAILED step rather than a throw: the loop decides what a failed step means. .PARAMETER Step A flattened step from Import-HDTSequenceDocument. .PARAMETER Context A New-HDTExecutionContext context. .OUTPUTS A New-HDTStepResult. .EXAMPLE Invoke-HDTSetVariableStep -Step $step -Context $context #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true)] [ValidateNotNull()] [object] $Step, [Parameter(Mandatory = $true)] [ValidateNotNull()] [object] $Context ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $property = $Step.Property $assignment = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::OrdinalIgnoreCase) if ($null -ne $property -and $property.Contains('variables') -and ($property['variables'] -is [System.Collections.IDictionary])) { foreach ($key in @($property['variables'].Keys)) { $assignment[[string] $key] = $property['variables'][$key] } } if ($null -ne $property -and $property.Contains('variable')) { $value = $null if ($property.Contains('value')) { $value = $property['value'] } $assignment[[string] $property['variable']] = $value } if (@($assignment.Keys).Count -eq 0) { $message = "step '{0}' declares no assignment. A SetVariable step declares either a variables mapping or a variable and value pair." -f $Step.Name Write-HDTLog -Context $Context.Log -Message $message -Severity Error -Event step.fail -Component 'SetVariable' return (New-HDTStepResult -Status Failed -Message $message) } foreach ($name in @($assignment.Keys)) { if ($name.StartsWith('_')) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord ` -Message ("step '{0}': '{1}' is engine-owned and cannot be assigned. A variable named _HDT* is set by the engine and is read-only." -f $Step.Name, $name))) } if ($name -cnotmatch '^HDT[A-Za-z0-9_]*$') { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord ` -Message ("step '{0}': '{1}' is not an HDT variable name. Every deployment variable is prefixed HDT; run Get-HDTVariableMap for the MDT translation." -f $Step.Name, $name))) } } foreach ($name in @($assignment.Keys)) { $unresolved = New-Object -TypeName System.Collections.ArrayList $raw = $assignment[$name] $value = $raw if ($raw -is [string]) { $value = Expand-HDTVariableToken -Value $raw -Scope $Context.Variable -Unresolved $unresolved } # The write is direct and overwriting, which is the whole difference # between this and Add-HDTResolvedVariable. $Context.Variable[$name] = $value $data = [ordered] @{ name = $name value = $value source = 'Step' step = [string] $Step.Name } if (@($unresolved).Count -gt 0) { $data['unresolved'] = [string[]] @($unresolved) } Write-HDTLog -Context $Context.Log -Event 'var.resolve' -Component 'SetVariable' ` -Message ("{0} = '{1}' (Step)" -f $name, $value) -Data $data if (@($unresolved).Count -gt 0) { Write-HDTLog -Context $Context.Log -Severity Warning -Event 'var.resolve' -Component 'SetVariable' ` -Message ("{0} variable token(s) were never supplied and are left unexpanded: {1}." -f @($unresolved).Count, (@($unresolved) -join ', ')) ` -Data ([ordered] @{ name = $name; source = 'Step'; step = [string] $Step.Name; unresolved = [string[]] @($unresolved) }) } } return (New-HDTStepResult -Status Completed ` -Message ("set {0}: {1}" -f @($assignment.Keys).Count, (@($assignment.Keys) -join ', '))) } |