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

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


I want to comment that the script in current accepted answer doesn't validate errors about incorrect orders of elements of xs:sequence. For example:test.xml

<addresses xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:noNamespaceSchemaLocation='test.xsd'>  <address>    <street>Baker street 5</street>    <name>Joe Tester</name>  </address></addresses>

test.xsd

<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>    <xs:element name="addresses">      <xs:complexType>       <xs:sequence>         <xs:element ref="address" minOccurs='1' maxOccurs='unbounded'/>       </xs:sequence>     </xs:complexType>    </xs:element>     <xs:element name="address">      <xs:complexType>       <xs:sequence>         <xs:element ref="name" minOccurs='0' maxOccurs='1'/>         <xs:element ref="street" minOccurs='0' maxOccurs='1'/>       </xs:sequence>      </xs:complexType>     </xs:element>     <xs:element name="name" type='xs:string'/>     <xs:element name="street" type='xs:string'/>    </xs:schema>

I wrote another version that can report this error:

function Test-XmlFile{    <#    .Synopsis        Validates an xml file against an xml schema file.    .Example        PS> dir *.xml | Test-XmlFile schema.xsd    #>    [CmdletBinding()]    param (             [Parameter(Mandatory=$true)]        [string] $SchemaFile,        [Parameter(ValueFromPipeline=$true, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]        [alias('Fullname')]        [string] $XmlFile,        [scriptblock] $ValidationEventHandler = { Write-Error $args[1].Exception }    )    begin {        $schemaReader = New-Object System.Xml.XmlTextReader $SchemaFile        $schema = [System.Xml.Schema.XmlSchema]::Read($schemaReader, $ValidationEventHandler)    }    process {        $ret = $true        try {            $xml = New-Object System.Xml.XmlDocument            $xml.Schemas.Add($schema) | Out-Null            $xml.Load($XmlFile)            $xml.Validate({                    throw ([PsCustomObject] @{                        SchemaFile = $SchemaFile                        XmlFile = $XmlFile                        Exception = $args[1].Exception                    })                })        } catch {            Write-Error $_            $ret = $false        }        $ret    }    end {        $schemaReader.Close()    }}

PS C:\temp\lab-xml-validation> dir test.xml | Test-XmlFile test.xsd

System.Xml.Schema.XmlSchemaValidationException: The element 'address' has invalid child element 'name'....


The PowerShell Community Extensions has a Test-Xml cmdlet. The only downside is the extensions havn't been updated for awhile, but most do work on the lastest version of powershell (including Test-Xml). Just do a Get-Childitem's and pass the list to a foreach, calling Test-Xml on each.


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"}}