对于我缺乏PowerShell知识的道歉,我一直在寻找解决方案,因为我不是一个程序员。
背景:
我目前正在尝试标准化Incapsula中的一些网站设置。要做到这一点,我想维护一个带有规则的本地XML,并使用一些PowerShell来下拉现有规则并将它们与那里的内容进行比较,以确保我不会加倍。我采用这种方法试图仅将增量应用为:
示例:
以下是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匹配的值进行比较?
如果您有任何其他问题,请与我们联系。
感谢。
答案 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。