Public/Get-CwSnapshot.ps1

function Get-CwSnapshot {
    <#
    .SYNOPSIS
        Creates the canonical JSON snapshot from the local collectors, or loads
        previously saved snapshots from disk.
    .DESCRIPTION
        Collect mode (default): runs Get-CwCertInventory and optionally
        Test-CwCrlHealth (-IncludeCrl), Get-CwCaHealth (-IncludeCA) and
        Test-CwEndpoint (-ProbeEndpoints) on the local machine and returns one
        normalized snapshot object - the canonical artifact every report and
        diff derives from.
 
        Load mode: -Path (+ -Latest / -Skip) reads snapshot JSON files back.
        '-Latest -Skip 1' returns the second-newest snapshot, which makes it
        the natural baseline for trend reports.
    .EXAMPLE
        Get-CwSnapshot -IncludeCrl -IncludeCA
    .EXAMPLE
        Get-CwSnapshot -Latest -Path .\snapshots -Skip 1
    #>

    [CmdletBinding(DefaultParameterSetName = 'Collect')]
    [OutputType([pscustomobject])]
    param(
        [Parameter(ParameterSetName = 'Collect')]
        [switch]$IncludeCrl,

        [Parameter(ParameterSetName = 'Collect')]
        [switch]$IncludeCA,

        [Parameter(ParameterSetName = 'Collect')]
        [string[]]$ProbeEndpoints,

        [Parameter(ParameterSetName = 'Collect')]
        [string]$Tenant,

        [Parameter(ParameterSetName = 'Collect')]
        [int]$WarnDays = 30,

        [Parameter(ParameterSetName = 'Collect')]
        [int]$CritDays = 7,

        [Parameter(ParameterSetName = 'Collect')]
        [double]$CrlWarnHours = 24,

        [Parameter(ParameterSetName = 'Collect')]
        [double]$CrlCritHours = 0,

        [Parameter(Mandatory, ParameterSetName = 'Load')]
        [string]$Path,

        [Parameter(ParameterSetName = 'Load')]
        [switch]$Latest,

        [Parameter(ParameterSetName = 'Load')]
        [int]$Skip = 0
    )

    if ($PSCmdlet.ParameterSetName -eq 'Load') {
        $files = if (Test-Path -Path $Path -PathType Container) {
            Get-ChildItem -Path $Path -Filter '*.json' -File | Sort-Object LastWriteTime -Descending
        }
        else {
            Get-Item -Path $Path
        }
        if ($Latest) {
            $files = $files | Select-Object -Skip $Skip -First 1
        }
        foreach ($file in $files) {
            Get-Content -Path $file.FullName -Raw | ConvertFrom-Json
        }
        return
    }

    # --- collect mode --------------------------------------------------------
    $certs = @(Get-CwCertInventory -WarnDays $WarnDays -CritDays $CritDays)

    $crls = @()
    if ($IncludeCrl) {
        $caCerts = @(Get-ChildItem -Path Cert:\LocalMachine\CA, Cert:\LocalMachine\Root -ErrorAction SilentlyContinue |
            Where-Object { $_.Extensions | Where-Object { $_.Oid.Value -eq '2.5.29.31' } } |
            Sort-Object Thumbprint -Unique)
        # only CAs that actually issued something in the local My store
        $relevantIssuers = @($certs | ForEach-Object Issuer | Sort-Object -Unique)
        $relevant = @($caCerts | Where-Object { $_.Subject -in $relevantIssuers })
        if ($relevant.Count -eq 0) { $relevant = $caCerts | Select-Object -First 5 }
        $crls = @($relevant | Test-CwCrlHealth -CheckCdp -WarnHours $CrlWarnHours -CritHours $CrlCritHours -ErrorAction SilentlyContinue)
    }

    $caHealth = $null
    if ($IncludeCA) {
        $caHealth = Get-CwCaHealth
    }

    $endpoints = @()
    if ($ProbeEndpoints) {
        $endpoints = @(Test-CwEndpoint -Uri $ProbeEndpoints -WarnDays $WarnDays -CritDays $CritDays)
    }

    [pscustomobject]@{
        PSTypeName    = 'CertWatchtower.Snapshot'
        SchemaVersion = '1.0'
        ToolVersion   = '1.0.0'
        Host          = $env:COMPUTERNAME
        Tenant        = $Tenant
        Timestamp     = (Get-Date).ToString('o')
        Thresholds    = [pscustomobject]@{
            WarnDays = $WarnDays; CritDays = $CritDays
            CrlWarnHours = $CrlWarnHours; CrlCritHours = $CrlCritHours
        }
        Certificates  = $certs
        Crls          = $crls
        CaHealth      = $caHealth
        Endpoints     = $endpoints
    }
}