在Powershell中比较对象,根据其中的一个字段为2个对象。由JSON和XML

时间:2018-02-21 02:57:27

标签: json powershell compareobject incapsula

对于我缺乏PowerShell知识的道歉,我一直在寻找解决方案,因为我不是一个程序员。

背景:

我目前正在尝试标准化Incapsula中的一些网站设置。要做到这一点,我想维护一个带有规则的本地XML,并使用一些PowerShell来下拉现有规则并将它们与那里的内容进行比较,以确保我不会加倍。我采用这种方法试图仅将增量应用为:

  1. 对于大多数设置,incapsula不够聪明,不知道它已经存在
  2. 可以发布到API的内容与API返回的内容有所不同
  3. 示例:

    以下是API将根据请求返回的示例,它采用JSON格式。

    JSON FROM WEBSITE
    
    {
    "security": {
            "waf": {
                "rules": [{
                    "id": "api.threats.sql_injection",
                    "exceptions": [{
                        "values": [{
                            "urls": [{
                                "value": "google.com/thisurl",
                                "pattern": "EQUALS"
                            }],
                            "id": "api.rule_exception_type.url",
                            "name": "URL"
                        }],
                        "id": 256354634
                    }]
                }, {
                    "id": "api.threats.cross_site_scripting",
                    "action": "api.threats.action.block_request",
                    "exceptions": [{
                        "values": [{
                            "urls": [{
                                "value": "google.com/anotherurl",
                                "pattern": "EQUALS"
                            }],
                            "id": "api.rule_exception_type.url",
                            "name": "URL"
                        }],
                        "id": 78908790780
                    }]
                }]
            }
        }
    }
    

    这是XML的格式,其中包含我们的特定网站设置

    OUR XML RULES
        <waf>
        <ruleset>
            <rule>
                <id>api.threats.sql_injection</id>
                    <exceptions>
                        <exception>
                            <type>api.rule_exception_type.url</type>
                            <url>google.com/thisurl</url>   
                        </exception>
                        <exception>
                            <type>api.rule_exception_type.url</type>
                            <url>google.com/thisanotherurl</url>
                        </exception>
                    </exceptions>
            </rule>
            <rule> 
                <id>api.threats.cross_site_scripting</id>
                    <exceptions>
                        <exception>
                            <type>api.rule_exception_type.url</type>
                            <url>google.com/anotherurl</url>
                        </exception>
                        <exception>
                            <type>api.rule_exception_type.url</type>
                            <url>google.com/anotherurl2</url>
                        </exception> 
                    </exceptions>
            </rule> 
        </ruleset>
    </waf>
    

    我已经成功地使用compare-object命令将站点中的其他设置与XML进行比较,但是它们的嵌套更简单,并没有给我带来太多麻烦。我坚持认为它是逻辑问题还是比较对象的限制。下面是一个示例代码,它将要求提供的json和xml在同一目录中保存为stack.json / xml,并且应该产生上述结果:

        $existingWaf = Get-Content -Path stack.json | ConvertFrom-Json
        [xml]$xmlFile = Get-Content -Path stack.xml 
    
        foreach ($rule in $xmlFile)
        {
            $ruleSet = $rule.waf.ruleset
        }
    
        foreach ($siteRule in $ExistingWaf.security.waf.rules)
            {
                foreach ($xmlRule in $ruleSet)
                {
                    if ($xmlRule.rule.id -eq $siteRule.id)
                        {
                            write-output "yes"
                            $delta = Compare-Object -ReferenceObject @($siteRule.exceptions.values.urls.value | Select-Object) -DifferenceObject @($xmlRule.rule.exceptions.exception.url | Select-Object) -IncludeEqual | where {$xmlRule.rule.id -eq $siteRule.id}
                            $delta
    
                        }
                }
            }
    

    这有点工作,但不是我想要的。我确实在对象之间进行了比较,但没有对具体的ID进行比较,它向我显示了以下结果:

        InputObject                                 SideIndicator
        -----------                                 -------------
        google.com/thisurl                               ==
        google.com/thisanotherurl                        =>
        google.com/anotherurl                            =>
        google.com/anotherurl2                           =>
    
        google.com/anotherurl                            ==
        google.com/thisurl                               =>
        google.com/thisanotherurl                        =>
        google.com/anotherurl2                           =>
    

    我更喜欢的地方

        InputObject                                 SideIndicator
        -----------                                 -------------
        google.com/thisurl                               ==
        google.com/thisanotherurl                        =>
    
        google.com/anotherurl                            ==
        google.com/anotherurl2                           =>
    

    希望这是有道理的。

    是否可以仅对ids匹配的值进行比较?

    如果您有任何其他问题,请与我们联系。

    感谢。

1 个答案:

答案 0 :(得分:0)

问题是您的迭代逻辑在一次迭代中错误地处理了来自XML文档的多个规则

  • foreach ($xmlRule in $ruleSet)没有枚举任何内容 - 而是处理了单个<ruleset>元素;要枚举孩子<rule>元素,您必须使用$ruleSet.rule

  • $xmlRule.rule.exceptions.exception.url然后隐式迭代所有 <rule>子项,因此会在所有中报告网址其中,它解释了Compare-Object输出中的额外行。

以下是代码的简化版注释版本:

$existingWaf = Get-Content -LiteralPath stack.json | ConvertFrom-Json
$xmlFile = [xml] (Get-Content -raw -LiteralPath stack.xml )

# No need for a loop; $xmlFile is a single [System.Xml.XmlDocument] instance.
$ruleSet = $xmlFile.waf.ruleset

foreach ($siteRule in $ExistingWaf.security.waf.rules)
{
    # !! Note the addition of `.rule`, which ensures that the rules
    # !! are enumerated *one by one*. 
    foreach ($xmlRule in $ruleSet.rule)
    {
        if ($xmlRule.id -eq $siteRule.id)
        {
          # !! Note: `$xmlRule` is now a single, rule, therefore:
          # `$xmlRule.rule.[...]-> `$xmlRule.[...]`
          # Also note that neither @(...) nor Select-Object are needed, and
          # the `| where ...` (Where-Object) is not needed.
          Compare-Object -ReferenceObject $siteRule.exceptions.values.urls.value `
                         -DifferenceObject $xmlRule.exceptions.exception.url -IncludeEqual
        }
    }
}

有关您的代码的其他观察

  • 无需确保传递给Compare-Object的操作数是数组,因此无需将它们包装在数组子表达式运算符@(...)中。 Compare-Object处理标量操作数。

  • ... | Select-Object是一个虚拟的 no-op - 输入对象通过 [1] 传递

  • ... | Where-Object {$xmlRule.rule.id -eq $siteRule.id}毫无意义,因为它复制了封闭的foreach循环条件。

    • 一般来说,由于您没有通过自动变量$_引用手头的管道输入对象,因此您的Where-Object过滤器静态并且匹配所有输入对象(如您的情况)或 none

[1] 一种微妙的,不可见的副作用,通常不会产生影响:Select-Object添加一个不可见的{{ 1}}包装在输入对象周围,在极少数情况下会导致以后不同的行为 -  见this GitHub issue