Support/Package/Schema/Eigenverft.Manifested.Package.Package.DefinitionCatalogValidation.ps1
|
<#
Eigenverft.Manifested.Package.Package.DefinitionCatalogValidation Read-only package-definition catalog validation helpers. #> function New-PackageDefinitionCatalogValidationIssue { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateSet('Error', 'Warning')] [string]$Severity, [Parameter(Mandatory = $true)] [string]$Code, [AllowNull()] [string]$Path = $null, [AllowNull()] [string]$PublisherId = $null, [AllowNull()] [string]$DefinitionId = $null, [AllowNull()] [string]$JsonPath = $null, [AllowNull()] [string]$Concept = $null, [Parameter(Mandatory = $true)] [string]$Message, [AllowNull()] [string]$SuggestedFix = $null ) return [pscustomobject]@{ Severity = $Severity Code = $Code Path = $Path PublisherId = $PublisherId DefinitionId = $DefinitionId JsonPath = $JsonPath Concept = $Concept Message = $Message SuggestedFix = $SuggestedFix } } function Add-PackageDefinitionCatalogValidationIssue { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [AllowEmptyCollection()] [System.Collections.Generic.List[object]]$Issues, [Parameter(Mandatory = $true)] [psobject]$Issue ) $Issues.Add($Issue) | Out-Null return $Issue } function ConvertTo-PackageDefinitionCatalogIdentityKey { [CmdletBinding()] param( [AllowNull()] [string]$PublisherId = $null, [AllowNull()] [string]$DefinitionId = $null ) if ([string]::IsNullOrWhiteSpace($PublisherId) -or [string]::IsNullOrWhiteSpace($DefinitionId)) { return $null } return ('{0}|{1}' -f ([string]$PublisherId).Trim().ToUpperInvariant(), ([string]$DefinitionId).Trim().ToUpperInvariant()) } function Get-PackageDefinitionCatalogValidationDisplayPath { [CmdletBinding()] param( [AllowNull()] [string]$Path = $null ) if ([string]::IsNullOrWhiteSpace($Path)) { return $Path } try { return [System.IO.Path]::GetFullPath($Path) } catch { return $Path } } function Get-PackageDefinitionCatalogValidationPathSet { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Path ) $issues = New-Object 'System.Collections.Generic.List[object]' $displayPath = Get-PackageDefinitionCatalogValidationDisplayPath -Path $Path try { $resolvedPath = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).Path } catch { Add-PackageDefinitionCatalogValidationIssue -Issues $issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code CatalogNoJsonFiles -Path $displayPath -Concept 'catalog.path' -Message ("Package-definition catalog path '{0}' could not be resolved." -f $displayPath) -SuggestedFix 'Provide an existing package-definition JSON file or endpoint folder path.') | Out-Null return [pscustomobject]@{ Path = $displayPath Kind = 'Missing' JsonPaths = @() Issues = @($issues.ToArray()) } } $kind = if (Test-Path -LiteralPath $resolvedPath -PathType Leaf) { 'File' } else { 'Directory' } $jsonPaths = if ([string]::Equals($kind, 'File', [System.StringComparison]::OrdinalIgnoreCase)) { @($resolvedPath) } else { @(Get-PackageDefinitionJsonPathsUnderDirectory -DirectoryPath $resolvedPath) } if ($jsonPaths.Count -eq 0) { Add-PackageDefinitionCatalogValidationIssue -Issues $issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code CatalogNoJsonFiles -Path $resolvedPath -Concept 'catalog.files' -Message ("Package-definition catalog path '{0}' does not contain any JSON files." -f $resolvedPath) -SuggestedFix 'Point the command at a package-definition JSON file or an endpoint folder containing JSON package definitions.') | Out-Null } return [pscustomobject]@{ Path = $resolvedPath Kind = $kind JsonPaths = @($jsonPaths) Issues = @($issues.ToArray()) } } function New-PackageDefinitionCatalogValidationEntry { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Path ) return [pscustomobject]@{ Path = $Path Parsed = $false SchemaValid = $false SchemaVersion = $null PublisherId = $null DefinitionId = $null SignatureStatus = $null SignatureValid = $false SignatureTrusted = $false Document = $null Issues = (New-Object 'System.Collections.Generic.List[object]') } } function Update-PackageDefinitionCatalogValidationEntryIdentity { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [psobject]$Entry, [AllowNull()] [psobject]$Document = $null ) if (-not $Document) { return } if ($Document.PSObject.Properties['schemaVersion']) { $Entry.SchemaVersion = [string]$Document.schemaVersion } if ($Document.PSObject.Properties['definitionPublication'] -and $Document.definitionPublication) { $publication = $Document.definitionPublication if ($publication.PSObject.Properties['publisherId']) { $Entry.PublisherId = [string]$publication.publisherId } if ($publication.PSObject.Properties['definitionId']) { $Entry.DefinitionId = [string]$publication.definitionId } } } function Add-PackageDefinitionCatalogSignatureIssue { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [psobject]$Entry, [Parameter(Mandatory = $true)] [psobject]$SignatureInfo, [switch]$RequireTrusted ) $status = [string]$SignatureInfo.Status $messageDetail = if ($SignatureInfo.PSObject.Properties['ErrorMessage'] -and -not [string]::IsNullOrWhiteSpace([string]$SignatureInfo.ErrorMessage)) { [string]$SignatureInfo.ErrorMessage } else { "Signature status is '$status'." } if ($status -in @('missingSignature', 'unsigned')) { $severity = if ($RequireTrusted.IsPresent) { 'Error' } else { 'Warning' } Add-PackageDefinitionCatalogValidationIssue -Issues $Entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity $severity -Code PackageDefinitionSignatureUnsigned -Path ([string]$Entry.Path) -PublisherId ([string]$Entry.PublisherId) -DefinitionId ([string]$Entry.DefinitionId) -JsonPath 'definitionPublication.definitionSignature' -Concept 'signature.trust' -Message ("Package definition '{0}' is unsigned or missing a signature." -f [string]$Entry.Path) -SuggestedFix 'Sign the package definition with Sign-PackageDefinition or omit -RequireTrusted for draft validation.') | Out-Null return } if ($status -in @('validUntrusted', 'unknownKey')) { $severity = if ($RequireTrusted.IsPresent) { 'Error' } else { 'Warning' } Add-PackageDefinitionCatalogValidationIssue -Issues $Entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity $severity -Code PackageDefinitionSignatureUntrusted -Path ([string]$Entry.Path) -PublisherId ([string]$Entry.PublisherId) -DefinitionId ([string]$Entry.DefinitionId) -JsonPath 'definitionPublication.definitionSignature' -Concept 'signature.trust' -Message ("Package definition '{0}' signature is not trusted. {1}" -f [string]$Entry.Path, $messageDetail) -SuggestedFix 'Trust the signing certificate, provide -CertificatePath for validation, or omit -RequireTrusted for non-strict validation.') | Out-Null return } if (-not [bool]$SignatureInfo.Valid) { Add-PackageDefinitionCatalogValidationIssue -Issues $Entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code PackageDefinitionSignatureInvalid -Path ([string]$Entry.Path) -PublisherId ([string]$Entry.PublisherId) -DefinitionId ([string]$Entry.DefinitionId) -JsonPath 'definitionPublication.definitionSignature' -Concept 'signature.validity' -Message ("Package definition '{0}' signature is invalid. {1}" -f [string]$Entry.Path, $messageDetail) -SuggestedFix 'Re-sign the package definition after fixing its JSON content, certificate metadata, or signature value.') | Out-Null return } if (-not [bool]$SignatureInfo.Trusted) { $severity = if ($RequireTrusted.IsPresent) { 'Error' } else { 'Warning' } Add-PackageDefinitionCatalogValidationIssue -Issues $Entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity $severity -Code PackageDefinitionSignatureUntrusted -Path ([string]$Entry.Path) -PublisherId ([string]$Entry.PublisherId) -DefinitionId ([string]$Entry.DefinitionId) -JsonPath 'definitionPublication.definitionSignature' -Concept 'signature.trust' -Message ("Package definition '{0}' signature is valid but not trusted." -f [string]$Entry.Path) -SuggestedFix 'Trust the signing certificate or omit -RequireTrusted for non-strict validation.') | Out-Null } } function Test-PackageDefinitionCatalogDocument { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Path, [AllowNull()] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate = $null, [AllowNull()] [psobject]$TrustInventoryDocument = $null, [switch]$RequireTrusted ) $entry = New-PackageDefinitionCatalogValidationEntry -Path $Path try { $definitionInfo = Read-PackageJsonDocument -Path $Path } catch { Add-PackageDefinitionCatalogValidationIssue -Issues $entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code CatalogJsonParseFailed -Path $Path -Concept 'json.parse' -Message $_.Exception.Message -SuggestedFix 'Fix the JSON syntax or file accessibility before validating schema and trust.') | Out-Null return $entry } $entry.Parsed = $true $entry.Document = $definitionInfo.Document Update-PackageDefinitionCatalogValidationEntryIdentity -Entry $entry -Document $definitionInfo.Document $expectedDefinitionId = if ([string]::IsNullOrWhiteSpace([string]$entry.DefinitionId)) { '<unknown>' } else { [string]$entry.DefinitionId } $expectedPublisherId = if ([string]::IsNullOrWhiteSpace([string]$entry.PublisherId)) { $null } else { [string]$entry.PublisherId } try { Assert-PackageDefinitionSchema -DefinitionDocumentInfo $definitionInfo -DefinitionId $expectedDefinitionId -PublisherId $expectedPublisherId $entry.SchemaValid = $true } catch { Add-PackageDefinitionCatalogValidationIssue -Issues $entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code PackageDefinitionSchemaInvalid -Path $Path -PublisherId ([string]$entry.PublisherId) -DefinitionId ([string]$entry.DefinitionId) -Concept 'schema.1.9' -Message $_.Exception.Message -SuggestedFix 'Update the package-definition JSON to satisfy the current schemaVersion 1.9 wire contract.') | Out-Null } try { $signatureInfo = Test-PackageDefinitionSignatureDocument -Definition $definitionInfo.Document -Certificate $Certificate -TrustInventoryDocument $TrustInventoryDocument $entry.SignatureStatus = [string]$signatureInfo.Status $entry.SignatureValid = [bool]$signatureInfo.Valid $entry.SignatureTrusted = [bool]$signatureInfo.Trusted Add-PackageDefinitionCatalogSignatureIssue -Entry $entry -SignatureInfo $signatureInfo -RequireTrusted:$RequireTrusted } catch { Add-PackageDefinitionCatalogValidationIssue -Issues $entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code PackageDefinitionSignatureInvalid -Path $Path -PublisherId ([string]$entry.PublisherId) -DefinitionId ([string]$entry.DefinitionId) -JsonPath 'definitionPublication.definitionSignature' -Concept 'signature.validity' -Message $_.Exception.Message -SuggestedFix 'Fix the definition signature metadata or re-sign the package definition.') | Out-Null } return $entry } function Add-PackageDefinitionCatalogValidationReferenceIssue { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [psobject]$Entry, [Parameter(Mandatory = $true)] [ValidateSet('Dependency', 'Policy')] [string]$ReferenceKind, [Parameter(Mandatory = $true)] [string]$JsonPath, [AllowNull()] [string]$ReferencePublisherId = $null, [AllowNull()] [string]$ReferenceDefinitionId = $null, [Parameter(Mandatory = $true)] [bool]$SelfReference ) if ([string]::Equals($ReferenceKind, 'Dependency', [System.StringComparison]::OrdinalIgnoreCase)) { $code = if ($SelfReference) { 'CatalogDependencySelfReference' } else { 'CatalogDependencyReferenceMissing' } $concept = 'dependency.requires' $message = if ($SelfReference) { "Package definition '$($Entry.DefinitionId)' references itself in dependency.requires." } else { "Package definition '$($Entry.DefinitionId)' references missing dependency '${ReferencePublisherId}:${ReferenceDefinitionId}'." } $fix = if ($SelfReference) { 'Remove the self dependency from dependency.requires.' } else { 'Add the referenced package definition to the validated endpoint folder or correct the dependency reference.' } } else { $code = if ($SelfReference) { 'CatalogPolicySelfReference' } else { 'CatalogPolicyReferenceMissing' } $concept = 'dependency.policy' $message = if ($SelfReference) { "Package definition '$($Entry.DefinitionId)' references itself in dependency.policy." } else { "Package definition '$($Entry.DefinitionId)' references missing dependency policy target '${ReferencePublisherId}:${ReferenceDefinitionId}'." } $fix = if ($SelfReference) { 'Remove the self reference from dependency.policy.' } else { 'Add the referenced package definition to the validated endpoint folder or correct the policy reference.' } } Add-PackageDefinitionCatalogValidationIssue -Issues $Entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code $code -Path ([string]$Entry.Path) -PublisherId ([string]$Entry.PublisherId) -DefinitionId ([string]$Entry.DefinitionId) -JsonPath $JsonPath -Concept $concept -Message $message -SuggestedFix $fix) | Out-Null } function Test-PackageDefinitionCatalogStaticReferences { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [AllowEmptyCollection()] [object[]]$Entries ) $schemaValidEntries = @($Entries | Where-Object { [bool]$_.SchemaValid }) $targetsByKey = @{} foreach ($entry in @($schemaValidEntries)) { $key = ConvertTo-PackageDefinitionCatalogIdentityKey -PublisherId ([string]$entry.PublisherId) -DefinitionId ([string]$entry.DefinitionId) if ($key) { $targetsByKey[$key] = $entry } } foreach ($entry in @($schemaValidEntries)) { $sourceKey = ConvertTo-PackageDefinitionCatalogIdentityKey -PublisherId ([string]$entry.PublisherId) -DefinitionId ([string]$entry.DefinitionId) $dependencyModel = Get-PackageDefinitionDependencyModel_1_9 -Definition $entry.Document -DefinitionId ([string]$entry.DefinitionId) $dependencyIndex = 0 foreach ($dependency in @($dependencyModel.Requires)) { if ($null -eq $dependency) { $dependencyIndex++ continue } $referencePublisherId = if ($dependency.PSObject.Properties['publisherId'] -and -not [string]::IsNullOrWhiteSpace([string]$dependency.publisherId)) { [string]$dependency.publisherId } else { [string]$entry.PublisherId } $referenceDefinitionId = if ($dependency.PSObject.Properties['definitionId']) { [string]$dependency.definitionId } else { $null } $referenceKey = ConvertTo-PackageDefinitionCatalogIdentityKey -PublisherId $referencePublisherId -DefinitionId $referenceDefinitionId $jsonPath = 'dependency.requires[{0}]' -f $dependencyIndex if ($referenceKey -and [string]::Equals($referenceKey, $sourceKey, [System.StringComparison]::OrdinalIgnoreCase)) { Add-PackageDefinitionCatalogValidationReferenceIssue -Entry $entry -ReferenceKind Dependency -JsonPath $jsonPath -ReferencePublisherId $referencePublisherId -ReferenceDefinitionId $referenceDefinitionId -SelfReference $true } elseif ($referenceKey -and -not $targetsByKey.ContainsKey($referenceKey)) { Add-PackageDefinitionCatalogValidationReferenceIssue -Entry $entry -ReferenceKind Dependency -JsonPath $jsonPath -ReferencePublisherId $referencePublisherId -ReferenceDefinitionId $referenceDefinitionId -SelfReference $false } $dependencyIndex++ } foreach ($policyPropertyName in @('conflictsWith', 'requiresAbsent')) { $policyReferences = if ($dependencyModel.Policy -and $dependencyModel.Policy.PSObject.Properties[$policyPropertyName]) { @($dependencyModel.Policy.$policyPropertyName) } else { @() } $policyIndex = 0 foreach ($policyReference in @($policyReferences)) { if ($null -eq $policyReference) { $policyIndex++ continue } $referencePublisherId = if ($policyReference.PSObject.Properties['publisherId'] -and -not [string]::IsNullOrWhiteSpace([string]$policyReference.publisherId)) { [string]$policyReference.publisherId } else { [string]$entry.PublisherId } $referenceDefinitionId = if ($policyReference.PSObject.Properties['definitionId']) { [string]$policyReference.definitionId } else { $null } $referenceKey = ConvertTo-PackageDefinitionCatalogIdentityKey -PublisherId $referencePublisherId -DefinitionId $referenceDefinitionId $jsonPath = 'dependency.policy.{0}[{1}]' -f $policyPropertyName, $policyIndex if ($referenceKey -and [string]::Equals($referenceKey, $sourceKey, [System.StringComparison]::OrdinalIgnoreCase)) { Add-PackageDefinitionCatalogValidationReferenceIssue -Entry $entry -ReferenceKind Policy -JsonPath $jsonPath -ReferencePublisherId $referencePublisherId -ReferenceDefinitionId $referenceDefinitionId -SelfReference $true } elseif ($referenceKey -and -not $targetsByKey.ContainsKey($referenceKey)) { Add-PackageDefinitionCatalogValidationReferenceIssue -Entry $entry -ReferenceKind Policy -JsonPath $jsonPath -ReferencePublisherId $referencePublisherId -ReferenceDefinitionId $referenceDefinitionId -SelfReference $false } $policyIndex++ } } } } function Add-PackageDefinitionCatalogDuplicateIdentityIssues { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [AllowEmptyCollection()] [object[]]$Entries ) $entriesByKey = @{} foreach ($entry in @($Entries | Where-Object { [bool]$_.SchemaValid })) { $key = ConvertTo-PackageDefinitionCatalogIdentityKey -PublisherId ([string]$entry.PublisherId) -DefinitionId ([string]$entry.DefinitionId) if (-not $key) { continue } if (-not $entriesByKey.ContainsKey($key)) { $entriesByKey[$key] = New-Object 'System.Collections.Generic.List[object]' } $entriesByKey[$key].Add($entry) | Out-Null } foreach ($key in @($entriesByKey.Keys)) { $duplicates = @($entriesByKey[$key].ToArray()) if ($duplicates.Count -le 1) { continue } $paths = (@($duplicates) | ForEach-Object { [string]$_.Path }) -join ', ' foreach ($entry in @($duplicates)) { Add-PackageDefinitionCatalogValidationIssue -Issues $entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity Error -Code CatalogDuplicateDefinitionIdentity -Path ([string]$entry.Path) -PublisherId ([string]$entry.PublisherId) -DefinitionId ([string]$entry.DefinitionId) -JsonPath 'definitionPublication' -Concept 'catalog.identity' -Message ("Package definition identity '{0}:{1}' appears more than once in this catalog: {2}" -f [string]$entry.PublisherId, [string]$entry.DefinitionId, $paths) -SuggestedFix 'Keep only one JSON file per publisherId and definitionId in the validated catalog folder.') | Out-Null } } } function Add-PackageDefinitionCatalogMixedSchemaVersionIssues { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [AllowEmptyCollection()] [object[]]$Entries, [switch]$StrictSchemaVersion ) $schemaVersions = @($Entries | Where-Object { [bool]$_.Parsed -and -not [string]::IsNullOrWhiteSpace([string]$_.SchemaVersion) } | ForEach-Object { [string]$_.SchemaVersion } | Sort-Object -Unique) if ($schemaVersions.Count -le 1) { return } $severity = if ($StrictSchemaVersion.IsPresent) { 'Error' } else { 'Warning' } $message = "Package-definition catalog contains mixed schemaVersion values: $($schemaVersions -join ', ')." foreach ($entry in @($Entries | Where-Object { [bool]$_.Parsed -and -not [string]::IsNullOrWhiteSpace([string]$_.SchemaVersion) })) { Add-PackageDefinitionCatalogValidationIssue -Issues $entry.Issues -Issue (New-PackageDefinitionCatalogValidationIssue -Severity $severity -Code CatalogMixedSchemaVersion -Path ([string]$entry.Path) -PublisherId ([string]$entry.PublisherId) -DefinitionId ([string]$entry.DefinitionId) -JsonPath 'schemaVersion' -Concept 'catalog.schemaVersion' -Message $message -SuggestedFix 'Use one supported schemaVersion across the endpoint folder, currently schemaVersion 1.9.') | Out-Null } } function New-PackageDefinitionCatalogValidationFileResult { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [psobject]$Entry ) $issues = @($Entry.Issues.ToArray()) return [pscustomobject]@{ Path = [string]$Entry.Path Parsed = [bool]$Entry.Parsed SchemaValid = [bool]$Entry.SchemaValid SchemaVersion = if ([string]::IsNullOrWhiteSpace([string]$Entry.SchemaVersion)) { $null } else { [string]$Entry.SchemaVersion } PublisherId = if ([string]::IsNullOrWhiteSpace([string]$Entry.PublisherId)) { $null } else { [string]$Entry.PublisherId } DefinitionId = if ([string]::IsNullOrWhiteSpace([string]$Entry.DefinitionId)) { $null } else { [string]$Entry.DefinitionId } SignatureStatus = if ([string]::IsNullOrWhiteSpace([string]$Entry.SignatureStatus)) { $null } else { [string]$Entry.SignatureStatus } SignatureValid = [bool]$Entry.SignatureValid SignatureTrusted = [bool]$Entry.SignatureTrusted ErrorCount = @($issues | Where-Object { [string]$_.Severity -eq 'Error' }).Count WarningCount = @($issues | Where-Object { [string]$_.Severity -eq 'Warning' }).Count Issues = @($issues) } } function Invoke-PackageDefinitionCatalogValidation { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Path, [AllowNull()] [string]$CertificatePath = $null, [switch]$RequireTrusted, [switch]$StrictSchemaVersion ) $pathSet = Get-PackageDefinitionCatalogValidationPathSet -Path $Path $certificate = $null $trustInventoryDocument = $null $entries = New-Object 'System.Collections.Generic.List[object]' try { if (@($pathSet.JsonPaths).Count -gt 0) { if (-not [string]::IsNullOrWhiteSpace($CertificatePath)) { $certificate = Import-PackageCertificate -Path $CertificatePath } else { $trustInventoryDocument = (Get-PackageTrustInventoryInfo).Document } foreach ($jsonPath in @($pathSet.JsonPaths)) { $entries.Add((Test-PackageDefinitionCatalogDocument -Path $jsonPath -Certificate $certificate -TrustInventoryDocument $trustInventoryDocument -RequireTrusted:$RequireTrusted)) | Out-Null } } if ([string]::Equals([string]$pathSet.Kind, 'Directory', [System.StringComparison]::OrdinalIgnoreCase)) { Add-PackageDefinitionCatalogDuplicateIdentityIssues -Entries @($entries.ToArray()) Add-PackageDefinitionCatalogMixedSchemaVersionIssues -Entries @($entries.ToArray()) -StrictSchemaVersion:$StrictSchemaVersion Test-PackageDefinitionCatalogStaticReferences -Entries @($entries.ToArray()) } } finally { if ($certificate) { $certificate.Dispose() } } $results = @( foreach ($entry in @($entries.ToArray())) { New-PackageDefinitionCatalogValidationFileResult -Entry $entry } ) $issues = @(@($pathSet.Issues) + @($results | ForEach-Object { @($_.Issues) })) $errorCount = @($issues | Where-Object { [string]$_.Severity -eq 'Error' }).Count $warningCount = @($issues | Where-Object { [string]$_.Severity -eq 'Warning' }).Count return [pscustomobject]@{ Path = [string]$pathSet.Path Kind = [string]$pathSet.Kind Valid = ($errorCount -eq 0) CheckedCount = $results.Count ParsedCount = @($results | Where-Object { [bool]$_.Parsed }).Count SchemaValidCount = @($results | Where-Object { [bool]$_.SchemaValid }).Count TrustedCount = @($results | Where-Object { [bool]$_.SignatureTrusted }).Count ErrorCount = $errorCount WarningCount = $warningCount RequireTrusted = [bool]$RequireTrusted.IsPresent StrictSchemaVersion = [bool]$StrictSchemaVersion.IsPresent Issues = @($issues) Results = @($results) } } |