Public/Test-EnvironmentFacts.ps1
|
function Test-EnvironmentFacts { <# .SYNOPSIS Verifies each fact in the database against the live environment. .DESCRIPTION Reads the facts database and dispatches each claim to the appropriate verification method (AD, DNS, CIM, network, etc.). Updates the facts.json file in place with actual values and verification status. .PARAMETER FactsPath Path to the facts.json database file. .PARAMETER ComputerName Additional servers to check via CIM sessions. .PARAMETER Credential PSCredential for remote server access. .PARAMETER SkipUnreachable Don't retry servers that were unreachable in the last run. .EXAMPLE Test-EnvironmentFacts -FactsPath .\facts.json .EXAMPLE Test-EnvironmentFacts -FactsPath .\facts.json -Credential (Get-Credential) -SkipUnreachable #> [CmdletBinding()] param( [Parameter(Mandatory, Position = 0)] [ValidateScript({ Test-Path $_ })] [string]$FactsPath, [Parameter()] [string[]]$ComputerName, [Parameter()] [PSCredential]$Credential, [Parameter()] [switch]$SkipUnreachable ) # Load facts database try { $factsDatabase = Get-Content -Path $FactsPath -Raw -Encoding UTF8 | ConvertFrom-Json } catch { throw "Failed to load facts database from '$FactsPath': $($_.Exception.Message)" } if (-not $factsDatabase.facts -or $factsDatabase.facts.Count -eq 0) { Write-Warning "No facts found in database." return [PSCustomObject]@{ TotalClaims = 0 Verified = 0 Drift = 0 Unreachable = 0 Unverifiable = 0 Pending = 0 } } # Build set of previously unreachable servers (if SkipUnreachable) $unreachableServers = @{} if ($SkipUnreachable) { foreach ($fact in $factsDatabase.facts) { foreach ($claim in $fact.claims) { if ($claim.status -eq 'unreachable') { $unreachableServers[$claim.subject] = $true } } } if ($unreachableServers.Count -gt 0) { Write-Verbose "Skipping $($unreachableServers.Count) previously unreachable servers." } } # Track verification statistics $stats = @{ TotalClaims = 0 Verified = 0 Drift = 0 Unreachable = 0 Unverifiable = 0 Pending = 0 } $verifyStart = Get-Date Write-Verbose "Starting verification of $($factsDatabase.facts.Count) facts..." # Process each fact and its claims for ($fi = 0; $fi -lt $factsDatabase.facts.Count; $fi++) { $fact = $factsDatabase.facts[$fi] Write-Verbose "Verifying fact: $($fact.id) - $($fact.source_text)" $factStatuses = @() for ($ci = 0; $ci -lt $fact.claims.Count; $ci++) { $claim = $fact.claims[$ci] $stats.TotalClaims++ Write-Verbose " Checking claim: $($claim.subject) / $($claim.claim_type) via $($claim.verification_method)" # Run the verification $verifiedClaim = Test-SingleFact -Claim $claim -Credential $Credential -UnreachableServers $unreachableServers # Update the claim in the database $fact.claims[$ci].actual_value = $verifiedClaim.actual_value $fact.claims[$ci].status = $verifiedClaim.status $fact.claims[$ci].last_checked = $verifiedClaim.last_checked $factStatuses += $verifiedClaim.status # Update counters switch ($verifiedClaim.status) { 'verified' { $stats.Verified++ } 'drift' { $stats.Drift++ } 'unreachable' { $stats.Unreachable++ } 'unverifiable' { $stats.Unverifiable++ } 'pending' { $stats.Pending++ } } Write-Verbose " Result: $($verifiedClaim.status) (actual: $($verifiedClaim.actual_value))" } # Determine overall fact status $fact.last_verified = (Get-Date).ToString('o') if ($factStatuses -contains 'drift') { $fact.overall_status = 'drift' } elseif ($factStatuses -contains 'unreachable') { $fact.overall_status = 'unreachable' } elseif ($factStatuses -contains 'unverifiable' -and $factStatuses -notcontains 'verified') { $fact.overall_status = 'unverifiable' } elseif ($factStatuses -contains 'verified') { $fact.overall_status = 'verified' } else { $fact.overall_status = 'pending' } # Update the database object $factsDatabase.facts[$fi] = $fact } # Update metadata $factsDatabase.metadata.last_verified = (Get-Date).ToString('o') $factsDatabase.metadata.total_facts = $factsDatabase.facts.Count $factsDatabase.metadata.verified = $stats.Verified $factsDatabase.metadata.drift_detected = $stats.Drift $factsDatabase.metadata.unverifiable = $stats.Unverifiable # Save updated facts database try { $factsDatabase | ConvertTo-Json -Depth 10 | Out-File -FilePath $FactsPath -Encoding UTF8 -Force Write-Verbose "Updated facts database saved to $FactsPath." } catch { Write-Warning "Could not save updated facts database: $($_.Exception.Message)" } $elapsed = (Get-Date) - $verifyStart Write-Verbose "Verification complete in $([Math]::Round($elapsed.TotalSeconds, 1)) seconds." # Return summary $summary = [PSCustomObject]@{ TotalClaims = $stats.TotalClaims Verified = $stats.Verified Drift = $stats.Drift Unreachable = $stats.Unreachable Unverifiable = $stats.Unverifiable Pending = $stats.Pending Duration = $elapsed FactsPath = $FactsPath } return $summary } |