Public/Export-NSPHandoff.ps1

function Export-NSPHandoff {
    <#
    .SYNOPSIS
        Writes a hand-off (from New-NSPHandoff) to a JSON file, with a SHA-256 of the payload so the
        reader can tell whether it was damaged or edited on the way.
 
    .DESCRIPTION
        The payload is serialized once and that exact text is both hashed and written, so the hash
        does not depend on which PowerShell edition reads the file later. Payload is always the last
        property in the file.
 
        With -Directory the file is named <Company>_<Tool>_<Kind>.json (Company reduced to letters,
        digits, - and _). Existing files are replaced.
 
    .PARAMETER Handoff
        Object from New-NSPHandoff.
 
    .PARAMETER Path
        Exact file to write.
 
    .PARAMETER Directory
        Folder to write into, using the standard file name.
 
    .EXAMPLE
        $h | Export-NSPHandoff -Directory C:\Temp
 
    .EXAMPLE
        Export-NSPHandoff -Handoff $h -Path C:\Temp\ExampleCo_NPS_Response.json
    #>

    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Directory')]
    [OutputType([IO.FileInfo])]
    param(
        [Parameter(Mandatory, ValueFromPipeline)][object]$Handoff,
        [Parameter(Mandatory, ParameterSetName = 'Path')][string]$Path,
        [Parameter(Mandatory, ParameterSetName = 'Directory')][string]$Directory
    )

    process {
        if ($Handoff.Envelope -ne 'NSP.Handoff') { throw 'Export-NSPHandoff takes an object from New-NSPHandoff.' }

        if ($PSCmdlet.ParameterSetName -eq 'Directory') {
            $Path = Join-Path $Directory (Get-NSPHandoffFileName -Company $Handoff.Company -Tool $Handoff.Tool -Kind $Handoff.Kind)
        }

        $payloadJson = if ($null -eq $Handoff.Payload) { 'null' } else { ConvertTo-Json -InputObject $Handoff.Payload -Depth 20 -Compress }
        $header = [ordered]@{}
        foreach ($p in $Handoff.PSObject.Properties) {
            if ($p.Name -in 'Payload', 'PayloadSha256') { continue }
            $header[$p.Name] = $p.Value
        }
        $header['PayloadSha256'] = Get-NSPTextSha256 $payloadJson
        $headerJson = (ConvertTo-Json -InputObject $header -Depth 5).TrimEnd()
        # Re-open the header object and append Payload as its last property, verbatim.
        $text = $headerJson.Substring(0, $headerJson.LastIndexOf('}')).TrimEnd() + ",`r`n `"Payload`": " + $payloadJson + "`r`n}`r`n"
        $text = ($text -replace "`r`n", "`n") -replace "`n", "`r`n"

        if ($PSCmdlet.ShouldProcess($Path, "Write $($Handoff.Tool) $($Handoff.Kind) hand-off")) {
            $parent = Split-Path -Parent $Path
            if ($parent -and -not (Test-Path -LiteralPath $parent)) { New-Item -ItemType Directory -Path $parent -Force | Out-Null }
            [IO.File]::WriteAllText($Path, $text, (New-Object Text.UTF8Encoding($false)))
            Get-Item -LiteralPath $Path
        }
    }
}