function Test-AlkamiManifest { <# .SYNOPSIS Test an AlkamiManifest.xml to ensure the file seems valid. .DESCRIPTION Test and AlkamiManifest.xml to ensure the file seems valid. This will return any of a number of errors, and a code. The message should have all the remediation information you need to resolve the error. The code should be supplied to an SDK/Tools team member for bug reporting or more detailed help. .PARAMETER Source [string] The folder that has the AlkamiManifest.xml file to be validated. Alternately, the path to the file. Defaults to looking in the current folder. .PARAMETER TargetObject [object] Used to bypass file loading. Most useful when combined with Get-PackageManifest -Path for ultimate power .INPUTS An AlkamiManifest.xml file for evaluation .OUTPUTS Either a successful message or a thrown error about what is broken. .EXAMPLE Test-AlkamiManifest [Test-AlkamiManifest] : The file at C:\my\test\AlkamiManifest.xml appears to be valid for processing. .EXAMPLE Test-AlkamiManifest C:\my\test\ [Test-AlkamiManifest] : The file at C:\my\test\AlkamiManifest.xml appears to be valid for processing. .EXAMPLE Test-AlkamiManifest C:\my\test\AlkamiManifest.xml [Test-AlkamiManifest] : The file at C:\my\test\AlkamiManifest.xml appears to be valid for processing. #> [CmdletBinding(DefaultParameterSetName = 'PassedPath')] [OutputType([bool])] Param( [Parameter(Mandatory = $false, ParameterSetName = 'PassedPath')] [ValidateNotNullOrEmpty()] [ValidateScript( {Test-Path (Resolve-Path $_)})] [Alias('Path', 'Folder', 'Target')] [String]$Source = ".", [Parameter(Mandatory = $true, ParameterSetName = 'PassedObject')] [object]$TargetObject ) $logLead = (Get-LogLeadName) $resultMessages = @() $success = $true $validateManifestNodes = @() #region parse/simplify parameterset if ($PSCmdlet.ParameterSetName -eq 'PassedPath') { $filename = (Get-AlkamiManifestFilename) $targetPath = Resolve-Path $Source if ((Split-Path $targetPath -Leaf) -ne $filename) { $targetPath = (Join-Path $targetPath $filename) } if (-not (Test-Path $targetPath)) { throw "$logLead : There is no file at $targetPath - Did you want to New-AlkamiManifest this file instead?" } $xmlContent = [Xml](Get-Content $targetPath) if ($null -eq $xmlContent.packageManifest) { throw "$logLead : There is no packageManifest tag in this file. It is invalid." } $TargetObject = $xmlContent.packageManifest } #endregion parse/simplify parameterset #region parse/validate version ## Add additional recognized version codes here. $recognizedVersionCodes = @('1.0') if (-not $TargetObject.version) { $resultMessages += 'There is no version tag in this file. It is invalid.' $success = $false } else { $version = $TargetObject.Version -replace '\.','' } if (-not ($recognizedVersionCodes -contains $TargetObject.version)) { $resultMessages += "The version tag in this file is unrecognized or unsupported. It is invalid. Valid values are [$($recognizedComponentTypes -join ',')]" $success = $false } #endregion parse/validate version # If we have gotten this far, we recognize the version and can test this manifest set if ($success) { #region parse/validate general if ($null -eq $TargetObject.general) { $resultMessages += 'There is no packageManifest/general tag in this file. It is invalid.' $success = $false } else { $validateManifestNodes += "General" } $recognizedComponentTypes = @( 'Widget' 'Service' 'FluentMigration' 'WebApplication' 'WebExtension' 'Repository' 'Provider' 'WebSite' 'Installer' 'SREModule' 'LegacyUtility' 'Hotfix' 'ApiComponent' ) $componentType = $TargetObject.general.componentType if ([string]::IsNullOrWhiteSpace($componentType)) { $resultMessages += 'The packageManifest/general/componentType tag in this file is missing or empty. It is invalid.' $success = $false } else { if (-not ($recognizedComponentTypes -contains $componentType)) { $resultMessages += "The packageManifest/general/componentType tag in this file is unrecognized or unsupported. Valid values are $($recognizedComponentTypes -join ',')" $success = $false } else { if ($componentType) { $validateManifestNodes += "$($componentType)Manifest" } } } #endregion parse/validate general foreach ($manifestNode in $validateManifestNodes) { $manifestFunctionName = $manifestNode if ($manifestNode -eq 'General') { # This is due to function name grouping so that they all appear together $manifestFunctionName = 'ManifestGeneral' } if ($manifestNode -eq "SREModuleManifest") { # This is due to Cole making a mistake in naming things $manifestFunctionName = 'SREModuleManifest' $manifestNode = 'moduleManifest' } if ($null -eq $TargetObject.$manifestNode) { $resultMessages += "The expected manifest type subnode [$manifestNode] was not found" $success = $false } # Create a simplified scriptblock that takes a param and executes a built-string against the provided object $dynamicString = "param (`$manifestObject) Test-Alkami$manifestFunctionName$version `$manifestObject" $sb = [scriptblock]::Create($dynamicString) $results = Invoke-Command -ScriptBlock $sb -ArgumentList @( $TargetObject.$manifestNode ) $resultMessages += @($results.results) $success = $success -and $results.Success } } foreach($resultMessage in $resultMessages) { if (-not [string]::IsNullOrWhiteSpace($resultMessage)) { Write-Warning $resultMessage } } return $success }