Public/Source/Test-IDBridgeSourceData.ps1
|
<# .SYNOPSIS Validate normalized source records and return only those that pass. .DESCRIPTION A thin, pure validator run over each source plugin's output inside Invoke-SourcePlugins. Records built by New-IDBridgeSourceRecord already have enforced field presence and types, so this focuses on cross-field business rules plus a safety net for records that bypass the factory. Invalid records are dropped and logged (Warn) with the plugin name for context; the remaining valid records are returned as an array. .PARAMETER InputObject The records returned by a source plugin. Null or empty is allowed (returns an empty array). .PARAMETER PluginName The plugin function name, used for log context. .EXAMPLE $sourceData += Test-IDBridgeSourceData -InputObject $pluginData -PluginName $plugin.Function .NOTES Created by: Sam Cattanach Modified: 2026-06-22 #> function Test-IDBridgeSourceData { [CmdletBinding()] [OutputType([object[]])] param ( [Parameter(Mandatory)][AllowNull()][AllowEmptyCollection()][object[]]$InputObject, [Parameter(Mandatory)][string]$PluginName ) $valid = [System.Collections.Generic.List[object]]::new() $total = 0 foreach ($record in $InputObject) { if ($null -eq $record) { continue } $total++ $reasons = [System.Collections.Generic.List[string]]::new() # Safety net (covers records that did not come through New-IDBridgeSourceRecord). if ([string]::IsNullOrWhiteSpace([string]$record.PersonID)) { $reasons.Add('missing PersonID') } if ($record.IDBActive -isnot [bool]) { $reasons.Add('IDBActive is not a boolean') } # Active Directory cross-field rules. if ($record.ProvisionAD -eq $true) { if ([string]::IsNullOrWhiteSpace([string]$record.ADOrganizationalUnit)) { $reasons.Add('ProvisionAD but ADOrganizationalUnit is empty') } if ([string]::IsNullOrWhiteSpace([string]$record.ADOrganizationalUnitTrash)) { $reasons.Add('ProvisionAD but ADOrganizationalUnitTrash is empty') } if (($record.ADKey -isnot [securestring]) -and ($record.ADPassphraseAPI -isnot [hashtable])) { $reasons.Add('ProvisionAD but no ADKey or ADPassphraseAPI') } } # Google Workspace cross-field rules. if ($record.ProvisionGoogle -eq $true) { if ([string]::IsNullOrWhiteSpace([string]$record.GoogleOrganizationalUnit)) { $reasons.Add('ProvisionGoogle but GoogleOrganizationalUnit is empty') } if ([string]::IsNullOrWhiteSpace([string]$record.GoogleOrganizationalUnitTrash)) { $reasons.Add('ProvisionGoogle but GoogleOrganizationalUnitTrash is empty') } if (($record.GoogleKey -isnot [securestring]) -and ($record.GooglePassphraseAPI -isnot [hashtable])) { $reasons.Add('ProvisionGoogle but no GoogleKey or GooglePassphraseAPI') } } if ($reasons.Count -gt 0) { $id = if ([string]::IsNullOrWhiteSpace([string]$record.PersonID)) { '<no PersonID>' } else { $record.PersonID } Write-Log -Message "Source Data: Plugin $PluginName - skipping PersonID ${id}: $($reasons -join '; ')" -Level Warn } else { $valid.Add($record) } } Write-Log -Message "Source Data: Plugin $PluginName - $($valid.Count)/$total records passed validation." -Level Trace return , $valid.ToArray() } |