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') { # First run friendly: a missing snapshot directory/file simply yields # nothing (e.g. -Baseline (Get-CwSnapshot -Latest ...) before any scan # has ever been persisted) instead of throwing. if (-not (Test-Path -Path $Path)) { Write-Verbose "Snapshot path '$Path' not found - nothing to load." return } $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) } $toolVersion = if ($MyInvocation.MyCommand.Module) { $MyInvocation.MyCommand.Module.Version.ToString() } else { '1.1.0' } [pscustomobject]@{ PSTypeName = 'CertWatchtower.Snapshot' SchemaVersion = '1.0' ToolVersion = $toolVersion 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 } } |