Powershell变量处理XML节点/路径



亲爱的Powershell专家你好,

我需要一些建议。我试着使用Powershell变量(我从参数)来解决XML路径/节点。

<我的场景/strong>

下面的代码显示了我的代码的一个简短的剪切。我将尽可能详细地解释我的问题。

foreach ($Gpo in $AllGpos) {
[xml]$selected_Gpo = Get-GPOReport -ReportType Xml -Guid $Gpo.Id
$policy_object = $selected_Gpo.GPO.Computer.ExtensionData.Extension
if ($policy_object.$Policy_Identity_XMLPath_Name -eq $Policy_Identity_Name) {
if ($policy_object.$Setting_XMLPath_Name -eq $Policy_Identity_Setting_Name -and $policy_object.$Setting_XMLPath_Value -eq $Policy_Identity_Setting_Value) {
}
...

遍历所有组策略对象(在Active Directory环境中),生成GPO的xml报告,然后在该xml文件中搜索特定的组策略设置。只要我使用硬编码的xml节点路径,这种方法就可以很好地工作。例如:而不是使用"$policy_object。$Policy_Identity_XMLPath_Name -eq $ policy_identity_name;我可以使用"$policy_object.Policy.DropDownList。名称-eq "设置示例"但是我无法使用这些硬编码的xml节点路径,并希望使用变量来解决xml文件中的这些路径。

一个示例XML的简写

<q1:Policy>
<q1:Name>TestName</q1:Name>
<q1:State>Enabled</q1:State>
<q1:Explain>Test Explaination </q1:Explain>
<q1:Supported>Testsupported version</q1:Supported>
<q1:Category>Test Category</q1:Category>
<q1:DropDownList>
<q1:Name>Test Name DropDownList</q1:Name>
<q1:State>Enabled</q1:State>
<q1:Value>
<q1:Name>TestName Value</q1:Name>
</q1:Value>
</q1:DropDownList>
</q1:Policy>

我的问题

问题是,我无法解决与powershell变量的xml路径。当我使用像上面代码样例中的变量($policy_object.$Policy_Identity_XMLPath_Name)时,我得到null返回,因此我的if语句不再工作。

我做了什么

当然我做了很多尝试和错误的事情,让powershell地址这些xml节点路径与变量。我试图把($policy_object.$Policy_Identity_XMLPath_Name)在不同类型的引号。我也已经看到了一个非常类似的问题堆栈溢出的帖子(解析一个XML文件与PowerShell节点从变量)但这些解决方案基本上没有那么糟糕,但在我的具体场景中没有用处。让我解释一下:

$Policy_Identity_Setting_XMLPath_Name = 'GPO/Computer/ExtensionData/Extension/SecurityOptions/Display/DisplayFields/Field/Name'
$test = policy_object.SelectNodes($Policy_Identity_Setting_XMLPath_Name)

=比;结果为空。真不知道为什么

$ExecutionContext.InvokeCommand.ExpandString("`$(`policy_object.$Policy_Identity_Setting_XMLPath_Name)")

这将导致一个"可接受的"结果。但在我的场景中,结果主要是多个值(GPO设置),并将它们全部存储在一个巨大的字符串中。之后我无法访问此字符串中的特定值。所以这种方法也不理想,因为我无法进一步处理结果。

我希望你们有一些好主意。也许在我的大脑逻辑中,我把它弄得太复杂了。如果你需要更多的信息,请告诉我。

如果你想使用PowerShell对XML DOM的适配,它允许使用.操作符对元素和属性进行类似属性的访问。,您可以通过将.分隔的路径字符串与.拆分为其组件来迭代地深入到XML文档,利用您可以使用表达式动态指定(单个)属性名称的事实:

# Sample input
[xml] $xml = @'
<q1:Policy xmlns:q1="http://example.org">
<q1:Name>TestName</q1:Name>
<q1:State>Enabled</q1:State>
<q1:Explain>Test Explaination </q1:Explain>
<q1:Supported>Testsupported version</q1:Supported>
<q1:Category>Test Category</q1:Category>
<q1:DropDownList>
<q1:Name>Test Name DropDownList</q1:Name>
<q1:State>Enabled</q1:State>
<q1:Value>
<q1:Name>TestName Value</q1:Name>
</q1:Value>
</q1:DropDownList>
</q1:Policy>
'@
# Define the path as a single, dotted string; e.g.:
$dottedPath = 'Policy.DropDownList.State'
# Drill down into the XML, component by component.
$result = $xml
foreach ($prop in $dottedPath -split '.') { $result = $result.$prop }
$result # Output the result: -> 'Enabled'

注意:PowerShell对XML DOM的适应很方便——值得注意的是不需要指定名称空间(见下文)——但也有其局限性;看到这个答案。


相比之下,为了使用XPath查询例如.SelectNodes():

  • 路径中的元素名必须用/分隔
  • 并且,由于文档使用XML名称空间,因此必须传递名称空间管理器实例作为第二个参数名称空间限定路径
  • 中的元素名称

如果你忽略了后者,你确实会得到$null作为结果。

# Sample input
[xml] $xml = @'
<q1:Policy xmlns:q1="http://example.org">
<q1:Name>TestName</q1:Name>
<q1:State>Enabled</q1:State>
<q1:Explain>Test Explaination </q1:Explain>
<q1:Supported>Testsupported version</q1:Supported>
<q1:Category>Test Category</q1:Category>
<q1:DropDownList>
<q1:Name>Test Name DropDownList</q1:Name>
<q1:State>Enabled</q1:State>
<q1:Value>
<q1:Name>TestName Value</q1:Name>
</q1:Value>
</q1:DropDownList>
</q1:Policy>
'@
# Create a namespace manager and associate it with the document.
$namespaceMgr = [System.Xml.XmlNamespaceManager]::new($xml.NameTable)
# Add an entry for the 'q1' namespace prefix.
# Note:
#  * The *prefix* (entry *name*) need not match the prefix in the document,
#    but whatever name you choose must be used in your XPath query.
#  * The namespace *URL* must match the one in the document, however.
$namespaceMgr.AddNameSpace('q1', 'http://example.org')
# Construct the XPath path, using the appropriate namespace prefixes; e.g.:
$xpath = 'q1:Policy/q1:DropDownList/q1:State'
# Now call .SelectNodes() with the query and the namespace manager.
# Note: This outputs the targeted XML element(s) as a whole, 
#       not their inner text, as dot notation would do.
#       Append .InnerText, if needed.
$xml.SelectNodes($xpath, $namespaceMgr)

注意:另外,考虑使用Select-Xmlcmdlet,它提供了一个高层次的接口。net api使用以上;看到这个答案的一个例子。