将Powershell XML输出匹配到模式

时间:2017-03-29 22:03:15

标签: powershell

我有一个返回JSON数据的监控系统。我使用Powershell来获取所有受监视的服务器及其属性的子集。然后我想将这些属性导出到与XSD匹配的XML文件,但我不知道该怎么做。

当我跑步时

$allServers | get-member

我可以在System.Management.Automation.PSCustomObject中看到服务器的所有属性。所以我跑:

$filtered = $allServers | Select-Object Id,HostName,Description,Status

好的,现在我拥有了我想要的属性,我可以运行这样的东西:

$filtered = ($filtered | ConvertTo-Xml)

现在我有一个System.Xml.XmlDocument对象。超。我可以使用保存方法:

$filtered.Save("c:\test\test.xml")

输出看起来没问题,但与所需的模式文件不匹配。

<?xml version="1.0" encoding="utf-8"?>
<Objects>
  <Object Type="System.Management.Automation.PSCustomObject">
    <Property Name="id" Type="System.Int32">6</Property>
    <Property Name="hostname" Type="System.String">server1</Property>
    <Property Name="description" Type="System.String">dc</Property>
    <Property Name="status" Type="System.Int32">1</Property>
  </Object>
</Objects>

我的架构如下所示:

<?xml version="1.0" encoding="Windows-1252"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified">
  <xsd:element name="ServerImport">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="Servers">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element maxOccurs="unbounded" name="Server">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="Id" type="xsd:int" />
                    <xsd:element name="HostName" type="xsd:string" />
                    <xsd:element name="Description" type="xsd:string" />
                    <xsd:element name="Status" type="xsd:int" />
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xs:schema>

那么,如何使输出与架构匹配?

感谢。

1 个答案:

答案 0 :(得分:1)

PowerShell的v5支持适当的类结构。因此,您可以创建一个包含所需信息的类,以及一个将类转换为XmlNode的小函数:

function makeXML($parentNode, $class) {

    $d = $parentNode.OwnerDocument.CreateElement($class.GetType().Name);
    $class.psobject.properties | foreach {
        $p = $doc.CreateElement($_.Name);
        $p.InnerText = $_.Value;
        $d.AppendChild($p);
    }

    $parentNode.AppendChild($d);
}

class Server { 
    [int]$Id; 
    [string]$HostName; 
    [string]$Description; 
    [int]$Status 
};

# Here you would need to convert the output from 
#     Select-Object ID,HostName,Description,Status
# to instances of type Server 

$s = New-Object server;
$s.Id = 1;
$s.HostName = "localhost";
$s.Description = "Local Server";
$s.Status = 3;

# Create the empty XML document to save your results to with root node of "Servers"
$doc = New-Object System.Xml.XmlDocument;
$doc.LoadXml("<ServerImport><Servers></Servers></ServerImport>");
$serversNode = $doc.SelectSingleNode("/ServerImport/Servers");

# This could likely be a pipe operation against your list of Server objects
# $filtered | { makeXml $serversNode $_ }
makeXML $serversNode $s;
# Save your xml to a file
$doc.Save("C:\test\test.xml");

这导致以下XML:

<ServerImport>
  <Servers>
    <Server>
      <Id>1</Id>
      <HostName>localhost</HostName>
      <Description>Local Server</Description>
      <Status>3</Status>
    </Server>
  </Servers>
</ServerImport>

注意:我确信有更优雅的解决方案,并且上述代码可能存在十几个增强功能。但是,这应该让你开始。

编辑 - 忽略了所需的XML结构(错过了ServerImport根节点)。