Private/Save-AGDeployState.ps1

function Save-AGDeployState {
    <#
    .SYNOPSIS
        Persists the deploy state file to disk.

    .DESCRIPTION
        Writes the in-memory state object (see New-AGDeployState) to disk as
        CLIXML so it is machine-readable and survives sessions and machines.
        This is the teardown source of truth. It is written before any AD
        change, and re-written as scenarios append clone records.

        The pre-change security descriptor binary form is serialized as a
        Base64 string inside the CLIXML so the byte array round-trips without
        loss.

    .PARAMETER State
        The state object produced by New-AGDeployState.

    .PARAMETER Path
        The destination file path. The module's deploy entrypoint passes a
        path next to the module root.

    .OUTPUTS
        None.

    .EXAMPLE
        Save-AGDeployState -State $state -Path "$PSScriptRoot/../ADCSGoat.State.xml"
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNull()]
        [pscustomobject]$State,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Path
    )

    process {
        # Flatten the byte array to Base64 for lossless CLIXML round-trip.
        $persisted = [pscustomobject]@{
            SelectedCA                        = $State.SelectedCA
            CapturedAt                        = $State.CapturedAt
            PreChangeCertificateTemplates     = @($State.PreChangeCertificateTemplates | ForEach-Object { "$_" })
            PreChangeSecurityDescriptorSddl   = $State.PreChangeSecurityDescriptorSddl
            PreChangeSecurityDescriptorBinaryBase64 = [Convert]::ToBase64String([byte[]]$State.PreChangeSecurityDescriptorBinary)
            Clones                            = @($State.Clones)
        }

        $directory = Split-Path -Path $Path -Parent
        if ($directory -and -not (Test-Path -Path $directory)) {
            New-Item -Path $directory -ItemType Directory -Force | Out-Null
        }

        $persisted | Export-Clixml -Path $Path -Force
        Write-Verbose "Deploy state written to '$Path'."
    }
}