Public/Export-CwCustomField.ps1

function Export-CwCustomField {
    <#
    .SYNOPSIS
        Maps snapshot key metrics onto RMM-specific custom-field writes
        (NinjaOne / Datto RMM / N-central).
    .DESCRIPTION
        Derives the standard metric set from a snapshot:
 
            NextExpiryDays, ExpiringCount, CrlHealthy, CaService, LastCheck
 
        and writes it to the target RMM:
          NinjaOne - via the agent-provided Ninja-Property-Set CLI
          DattoRMM - UDF via HKLM:\SOFTWARE\CentraStage Custom<N>
          NCentral - key=value lines on stdout (Automation Manager parsing)
 
        Always returns the metrics object, so the caller can also feed other
        systems. Provider writes are skipped with a warning when the agent
        context is not available (e.g. Ninja CLI missing).
    .EXAMPLE
        Get-CwSnapshot -IncludeCrl -IncludeCA | Export-CwCustomField -Provider NinjaOne
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [object]$Snapshot,

        [Parameter(Mandatory)]
        [ValidateSet('NinjaOne', 'DattoRMM', 'NCentral')]
        [string]$Provider,

        # NinjaOne custom field name prefix (fields: <prefix>NextExpiryDays, ...)
        [string]$FieldPrefix = 'cert',

        # Datto RMM UDF number (writes Custom<N>)
        [ValidateRange(1, 30)]
        [int]$DattoUdf = 10
    )

    process {
        $certs = @($Snapshot.Certificates)
        $warnDays = 30
        if ($Snapshot.PSObject.Properties['Thresholds'] -and $Snapshot.Thresholds -and
            $Snapshot.Thresholds.PSObject.Properties['WarnDays']) {
            $warnDays = [double]$Snapshot.Thresholds.WarnDays
        }

        $next = $certs | Sort-Object { [double]$_.DaysRemaining } | Select-Object -First 1
        $crls = @($Snapshot.Crls)
        $crlHealthy = if ($crls.Count -eq 0) { $null }
        else { @($crls | Where-Object { $_.Severity -in 'WARNING', 'CRITICAL' }).Count -eq 0 }

        $caService = $null
        if ($Snapshot.CaHealth -and $Snapshot.CaHealth.IsCa) {
            $caService = $Snapshot.CaHealth.ServiceStatus
        }

        $metrics = [pscustomobject]@{
            PSTypeName     = 'CertWatchtower.Metrics'
            Host           = $Snapshot.Host
            NextExpiryDays = if ($next) { [math]::Floor([double]$next.DaysRemaining) } else { $null }
            NextSubject    = if ($next) { $next.Subject } else { $null }
            NextRole       = if ($next) { $next.Role } else { $null }
            ExpiringCount  = @($certs | Where-Object { [double]$_.DaysRemaining -le $warnDays }).Count
            CrlHealthy     = $crlHealthy
            CaService      = $caService
            LastCheck      = (Get-Date -Format o)
        }

        switch ($Provider) {
            'NinjaOne' {
                if (Get-Command -Name 'Ninja-Property-Set' -ErrorAction SilentlyContinue) {
                    if ($PSCmdlet.ShouldProcess('NinjaOne custom fields', 'Ninja-Property-Set')) {
                        Ninja-Property-Set "$($FieldPrefix)NextExpiryDays" $metrics.NextExpiryDays
                        Ninja-Property-Set "$($FieldPrefix)ExpiringCount" $metrics.ExpiringCount
                        Ninja-Property-Set "$($FieldPrefix)CrlHealthy" $metrics.CrlHealthy
                        Ninja-Property-Set "$($FieldPrefix)CaService" $metrics.CaService
                        Ninja-Property-Set "$($FieldPrefix)LastCheck" $metrics.LastCheck
                    }
                }
                else {
                    Write-Warning 'Ninja-Property-Set CLI not found - not running in a NinjaOne agent context.'
                }
            }
            'DattoRMM' {
                $regPath = 'HKLM:\SOFTWARE\CentraStage'
                if ($PSCmdlet.ShouldProcess("$regPath Custom$DattoUdf", 'Write UDF')) {
                    if (-not (Test-Path -Path $regPath)) {
                        Write-Warning "Registry path $regPath not found - not running under a Datto RMM agent."
                    }
                    else {
                        $value = "NextExpiry=$($metrics.NextExpiryDays)d Expiring=$($metrics.ExpiringCount) CRL=$(if ($null -eq $metrics.CrlHealthy) { 'n/a' } elseif ($metrics.CrlHealthy) { 'ok' } else { 'FAIL' })"
                        New-ItemProperty -Path $regPath -Name "Custom$DattoUdf" -Value $value -PropertyType String -Force | Out-Null
                    }
                }
            }
            'NCentral' {
                # N-central Automation Manager reads stdout key=value pairs
                Write-Output "certNextExpiryDays=$($metrics.NextExpiryDays)"
                Write-Output "certExpiringCount=$($metrics.ExpiringCount)"
                Write-Output "certCrlHealthy=$($metrics.CrlHealthy)"
                Write-Output "certCaService=$($metrics.CaService)"
                Write-Output "certLastCheck=$($metrics.LastCheck)"
            }
        }

        $metrics
    }
}