Search code examples
xmlpowershellxsd

How do I use PowerShell to Validate XML files against an XSD?


As a part of my development I'd like to be able to validate an entire folder's worth of XML files against a single XSD file. A PowerShell function seems like a good candidate for this as I can then just pipe a list of files to it like so: dir *.xml | Validate-Xml -Schema .\MySchema.xsd

I've considered porting C# code from the Validating an Xml against Referenced XSD in C# question, but I don't know how to Add handlers in PowerShell.


Solution

  • I wrote a PowerShell function to do this:

    Usage:

    dir *.xml | Test-Xml -Schema ".\MySchemaFile.xsd" -Namespace "http://tempuri.org"
    

    Code:

    function Test-Xml {
        param(
            $InputObject = $null,
            $Namespace = $null,
            $SchemaFile = $null
        )
    
        BEGIN {
            $failCount = 0
            $failureMessages = ""
            $fileName = ""
        }
    
        PROCESS {
            if ($InputObject -and $_) {
                throw 'ParameterBinderStrings\AmbiguousParameterSet'
                break
            } elseif ($InputObject) {
                $InputObject
            } elseif ($_) {
                $fileName = $_.FullName
                $readerSettings = New-Object -TypeName System.Xml.XmlReaderSettings
                $readerSettings.ValidationType = [System.Xml.ValidationType]::Schema
                $readerSettings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessInlineSchema -bor
                    [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessSchemaLocation -bor 
                    [System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings
                $readerSettings.Schemas.Add($Namespace, $SchemaFile) | Out-Null
                $readerSettings.add_ValidationEventHandler(
                {
                    $failureMessages = $failureMessages + [System.Environment]::NewLine + $fileName + " - " + $_.Message
                    $failCount = $failCount + 1
                });
                $reader = [System.Xml.XmlReader]::Create($_, $readerSettings)
                while ($reader.Read()) { }
                $reader.Close()
            } else {
                throw 'ParameterBinderStrings\InputObjectNotBound'
            }
        }
    
        END {
            $failureMessages
            "$failCount validation errors were found"
        }
    }