Public/Merge-NSPHandoffAnswers.ps1
|
function Merge-NSPHandoffAnswers { <# .SYNOPSIS Merges incoming answers (a shim's seed, a re-staged snapshot) into the live answers a tool already has, field by field, and returns the result. Writes nothing. .DESCRIPTION The ShimEngine rule the zip-era shims used: - a field only the live answers have is kept (never destroyed); - a field only the incoming answers have is added; - a field that is the same in both needs no decision; - a field that differs keeps the live value, unless the operator takes the incoming one. Differing fields are prompted for one at a time - keep (L)ive, take (I)ncoming, take (A)ll incoming from here, (S)kip the rest - unless -NonInteractive or -TakeIncoming is given, or the session cannot prompt, in which case live wins. Long values are shortened on screen. Returns an object: Answers (the merged answers), Added, Differing, TookIncoming (counts). .PARAMETER Live The answers the tool has now ($null when it has none - incoming is then taken as-is). .PARAMETER Incoming The answers arriving. .PARAMETER NonInteractive Never prompt; live wins every differing field. .PARAMETER TakeIncoming Never prompt; incoming wins every differing field. .EXAMPLE $r = Merge-NSPHandoffAnswers -Live (Get-NSPToolAnswers -Tool NPS) -Incoming $seed Save-NSPToolAnswers -Tool NPS -Answers $r.Answers #> [CmdletBinding()] param( [AllowNull()][object]$Live, [Parameter(Mandatory)][object]$Incoming, [switch]$NonInteractive, [switch]$TakeIncoming ) $Incoming = ConvertTo-NSPAnswersObject $Incoming if ($null -eq $Live) { $count = @($Incoming.PSObject.Properties).Count return [pscustomobject]@{ Answers = $Incoming; Added = $count; Differing = 0; TookIncoming = 0 } } $Live = ConvertTo-NSPAnswersObject $Live $liveNames = @($Live.PSObject.Properties | ForEach-Object Name) $incomingNames = @($Incoming.PSObject.Properties | ForEach-Object Name) $allNames = @($liveNames + ($incomingNames | Where-Object { $liveNames -notcontains $_ })) $result = [ordered]@{} $added = 0; $differing = 0; $tookIncoming = 0 $takeAll = [bool]$TakeIncoming $keepRest = [bool]$NonInteractive foreach ($name in $allNames) { $inLive = $liveNames -contains $name $inIncoming = $incomingNames -contains $name if ($inLive -and -not $inIncoming) { $result[$name] = $Live.$name; continue } if ($inIncoming -and -not $inLive) { $result[$name] = $Incoming.$name; $added++; continue } $liveJson = ConvertTo-Json -InputObject $Live.$name -Compress -Depth 20 $incomingJson = ConvertTo-Json -InputObject $Incoming.$name -Compress -Depth 20 if ($liveJson -eq $incomingJson) { $result[$name] = $Live.$name; continue } $differing++ $choice = 'Live' if ($takeAll) { $choice = 'Incoming' } elseif (-not $keepRest) { Write-Host " - ${name}:" -ForegroundColor Yellow Write-Host " LIVE (on this server) : $(Get-NSPShortText $liveJson)" -ForegroundColor DarkCyan Write-Host " INCOMING : $(Get-NSPShortText $incomingJson)" -ForegroundColor Magenta $answer = $null try { $answer = Read-Host ' Keep (L)ive, take (I)ncoming, take (A)ll incoming from here, or (S)kip the rest (keep live)?' } catch { Write-Host ' (Cannot prompt in this session - keeping LIVE for this and the remaining fields.)' -ForegroundColor Yellow $keepRest = $true } switch -Regex ([string]$answer) { '^(?i)i$' { $choice = 'Incoming' } '^(?i)a$' { $choice = 'Incoming'; $takeAll = $true } '^(?i)s$' { $keepRest = $true } } } if ($choice -eq 'Incoming') { $result[$name] = $Incoming.$name; $tookIncoming++ } else { $result[$name] = $Live.$name } } [pscustomobject]@{ Answers = [pscustomobject]$result; Added = $added; Differing = $differing; TookIncoming = $tookIncoming } } |