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 candid
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 re-wrote it (I know bad habbit) , but the starting script by @Flatliner_DOA was too good to discard completely.
function Test-Xml {
[cmdletbinding()]
param(
[parameter(mandatory=$true)]$InputFile,
$Namespace = $null,
[parameter(mandatory=$true)]$SchemaFile
)
BEGIN {
$failCount = 0
$failureMessages = ""
$fileName = ""
}
PROCESS {
if ($inputfile)
{
write-verbose "input file: $inputfile"
write-verbose "schemafile: $SchemaFile"
$fileName = (resolve-path $inputfile).path
if (-not (test-path $SchemaFile)) {throw "schemafile not found $schemafile"}
$readerSettings = New-Object -TypeName System.Xml.XmlReaderSettings
$readerSettings.ValidationType = [System.Xml.ValidationType]::Schema
$readerSettings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessIdentityConstraints -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ProcessSchemaLocation -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings
$readerSettings.Schemas.Add($Namespace, $SchemaFile) | Out-Null
$readerSettings.add_ValidationEventHandler(
{
try {
$detail = $_.Message
$detail += "`n" + "On Line: $($_.exception.linenumber) Offset: $($_.exception.lineposition)"
} catch {}
$failureMessages += $detail
$failCount = $failCount + 1
});
try {
$reader = [System.Xml.XmlReader]::Create($fileName, $readerSettings)
while ($reader.Read()) { }
}
#handler to ensure we always close the reader sicne it locks files
finally {
$reader.Close()
}
} else {
throw 'no input file'
}
}
END {
if ($failureMessages)
{ $failureMessages}
write-verbose "$failCount validation errors were found"
}
}
#example calling/useage code follows:
$erroractionpreference = 'stop'
Set-strictmode -version 2
$valid = @(Test-Xml -inputfile $inputfile -schemafile $XSDPath )
write-host "Found ($($valid.count)) errors"
if ($valid.count) {
$valid |write-host -foregroundcolor red
}
The function no longer pipelines as an alternative to using a file-path, it's a complication this use-case does not need. Feel free to hack the begin/process/end handlers away.