Public/Save-HDTRunState.ps1
|
function Save-HDTRunState { <# .SYNOPSIS Checkpoints the run state document through the injected IFileSystem. .DESCRIPTION state.json lives at X:\HDT\state.json in WinPE and C:\HDT\state.json in the full OS, and requires it to be "mirrored to the target disk's \HDT\ as soon as a formatted volume exists. The mirror is what makes the WinPE to OS transition survivable" - the RAM disk the WinPE copy lives on does not exist after the reboot. -MirrorPath writes the SAME serialised bytes to a second location, so a resume can read whichever copy survived. updatedUtc is stamped from the injected clock on every save, which is what Test-HDTRunStateAbandoned later reads to tell a live deployment from one that died between legs. startedUtc is left alone. The write goes through IFileSystem.WriteAllText, never a file-writing cmdlet: the adapter writes UTF-8 without a byte order mark, and the whole checkpoint path has to be provable with nothing on disk. .PARAMETER State A New-HDTRunState or Import-HDTRunState result. Its updatedUtc is mutated in place, so the caller's copy stays in step with the file. .PARAMETER Path Where to write it, conventionally X:\HDT\state.json or C:\HDT\state.json. .PARAMETER FileSystem An IFileSystem - New-HDTFileSystem in production, New-HDTFakeFileSystem in a test. .PARAMETER Clock An IClock, used to stamp updatedUtc. Mandatory: PROJECT constraint 4 forbids engine logic from reading the wall clock directly. .PARAMETER MirrorPath A second location to write the identical document to, conventionally the target volume's \HDT\state.json once one is formatted. .OUTPUTS None. .EXAMPLE Save-HDTRunState -State $state -Path 'X:\HDT\state.json' ` -FileSystem $fileSystem -Clock $clock -MirrorPath 'W:\HDT\state.json' #> [CmdletBinding(SupportsShouldProcess = $true)] [OutputType([void])] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNull()] [object] $State, [Parameter(Mandatory = $true, Position = 1)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory = $true)] [ValidateNotNull()] [object] $FileSystem, [Parameter(Mandatory = $true)] [ValidateNotNull()] [object] $Clock, [Parameter()] [ValidateNotNullOrEmpty()] [string] $MirrorPath ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $State.updatedUtc = $Clock.GetUtcNow().ToUniversalTime().ToString('o', [System.Globalization.CultureInfo]::InvariantCulture) # Serialised once, so the mirror is byte-for-byte the document at Path. $json = ConvertTo-Json -InputObject $State -Depth 8 if ($PSCmdlet.ShouldProcess($Path, 'Write run state')) { $FileSystem.WriteAllText($Path, $json) } if ($PSBoundParameters.ContainsKey('MirrorPath')) { if ($PSCmdlet.ShouldProcess($MirrorPath, 'Mirror run state')) { $FileSystem.WriteAllText($MirrorPath, $json) } } } |