根据错误结果,在文件中循环(使用Powershell)并一次移动一个文件时出现问题

根据错误结果,在文件中循环(使用Powershell)并一次移动一个文件时出现问题,powershell,if-statement,foreach,Powershell,If Statement,Foreach,我使用Powershell针对多个XSD验证多个XML文件;这部分代码按预期工作,但是我还需要将任何无法验证的XML移到“无效”文件夹中。我试图使用ForEach循环遍历这些文件,然后使用If语句移动出错的任何文件。我的问题是所有文件都在移动,不管它们是否出错 我已经用我能想到的许多不同的方式写了这个循环,但是我没有得到我期望的结果。(我也在网上搜索了好几天才找到答案。)我需要ForEach将代码应用于每个文件,一次一个。这是我的语法问题吗?也许我遗漏了一些非常明显的东西,但我现在不知所措 我使

我使用Powershell针对多个XSD验证多个XML文件;这部分代码按预期工作,但是我还需要将任何无法验证的XML移到“无效”文件夹中。我试图使用ForEach循环遍历这些文件,然后使用If语句移动出错的任何文件。我的问题是所有文件都在移动,不管它们是否出错

我已经用我能想到的许多不同的方式写了这个循环,但是我没有得到我期望的结果。(我也在网上搜索了好几天才找到答案。)我需要ForEach将代码应用于每个文件,一次一个。这是我的语法问题吗?也许我遗漏了一些非常明显的东西,但我现在不知所措

我使用这个函数(在堆栈溢出上找到,如图所示,稍微调整)来验证XML

function Test-XmlFile
{
    <#
    .Synopsis
        Validates an xml file against an xml schema file.
    .Example
        PS> dir *.xml | Test-XmlFile schema.xsd
    #>
    [CmdletBinding()]
    param (     
        [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
        [SupportsWildcards()]
        $SchemaFile,

        [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
        [SupportsWildcards()]
        [alias('Fullname')]
        $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()
    }
}
对于$xml2和$xsd2变量,上面的ForEach循环也会重复。 (正如您从Out文件中看到的,我还在一个文本文件中捕获异常消息,用于排序日志。)

由于“If($error)”语句和我试图一次一个循环遍历文件的事实,我只希望移动那些出错并遇到异常的XML;但是,所发生的情况是,任何包含唯一字符串的XML(该字符串将其标识为$xml1或$xml2组的一部分)都会被移动到无效文件夹中,错误或无错误。那么,我错过了什么显而易见的痛苦呢??(顺便说一句,异常文本按预期填充错误日志,因此至少该部分工作正常。)


编辑:再想一想,我不应该说异常文本“按预期”填充日志。它确实会填充日志,但对于变量中包含的每个文件(例如$xml1中的每个文件),它会将消息写入日志文件一次,而不管该文件是否实际出错。因此,如果$xml1中有两个文件,但只有一个无效,则该无效文件的单个异常消息将写入日志两次。因此,它为循环的每个文件编写一些内容,而不管是否存在有效性或错误。希望这是有意义的。

$Error
为您提供了上一次错误的列表,如果上一次操作成功,它不会被清除-它仍将包含上一次遇到的错误。因此,在出现第一个错误后,每个文件都将被复制到“无效”目录


您的cmdlet中已经有错误处理,因此您可以修改该代码以同时处理将文件移动到其他目录的操作

您的
testxmlfile
函数输出一个布尔值,指示验证的成功状态,因此我建议直接使用它来确定验证成功与失败;此外,要捕获验证失败的细节,请使用
-ErrorVariable
公共参数:

ForEach ($xml in $xml1) {
  if (-not (Test-XmlFile -XmlFile $xml -SchemaFile $xsd1 -ErrorVariable err)) {
    $err.Exception, "`n" | Out-File -Append "..\Schema Validation\Results\log.txt"
    Move-Item $xml -Destination "..\Schema Validation\Invalid"
  }
}
请注意,我已将
-Append
添加到您的
输出文件
调用中,以确保多个故障不会在日志文件中相互覆盖。此外,最好使用
“`n”
“`r`n”
或适当地使用
[Environment]::NewLine]
创建换行符(换行符)


至于你所尝试的:

自动
$Error
变量是当前会话中发生的所有错误的集合(类型为
[System.Collections.ArrayList]

因此,如果使用
if($Error)
,实际上是询问到目前为止会话中是否至少发生了一个错误,而不是最近执行的命令是否报告了错误(最后一个错误将反映在
$Error[0]
),因为一旦集合至少有一个条目,布尔上下文中的
$Error
就会计算为
$true

还有自动的
$?
变量,它是一个布尔值,指示最近执行的命令是否报告了错误(至少一个错误)-不幸的是,这种行为存在不一致性(任何表达式都会将
$?
重置为
$true
,并且
写入错误
不会将
$?
设置为
$false
,这与报告错误的已编译cmdlet不同),因此在您的情况下,最好依赖
测试XmlFile
的显式布尔返回值。

“上次错误”有点让人困惑;automatic
$Error
变量是当前会话中发生的所有错误的集合,按逆时间顺序排列。
ForEach ($xml in $xml1) {
$xml | Test-XmlFile $xsd1
If ($Error) {
$Error[0].Exception, "`r" | Out-File "..\Schema Validation\Results\log.txt"
Move-Item $xml -Destination "..\Schema Validation\Invalid"
}}
ForEach ($xml in $xml1) {
  if (-not (Test-XmlFile -XmlFile $xml -SchemaFile $xsd1 -ErrorVariable err)) {
    $err.Exception, "`n" | Out-File -Append "..\Schema Validation\Results\log.txt"
    Move-Item $xml -Destination "..\Schema Validation\Invalid"
  }
}