使用PowerShell的ForEach XML文件

时间:2018-01-29 17:57:35

标签: xml powershell foreach

我在4.1423 有一个包含以下信息的XML文件:

$DSConfigPath

我的目标是对<dataSources> <add id="DataSource1" type="Fixed" distance="1"> <parameters> <name /> <address>10.1.1.10</address> <otherIdentifiers>DataSource1</otherIdentifiers> <activeStatus>true</activeStatus> <ip>10.1.1.10</ip> <port>952</port> </parameters> </add> <add id="DataSource2" type="Fixed" distance="2"> <parameters> <name /> <address>10.1.1.11</address> <otherIdentifiers>DataSource2</otherIdentifiers> <activeStatus>true</activeStatus> <ip>10.1.1.11</ip> <port>952</port> </parameters> </add> <add id="DataSource3" type="Fixed" distance="3"> <parameters> <name /> <address>10.1.1.12</address> <otherIdentifiers>DataSource1</otherIdentifiers> <activeStatus>false</activeStatus> <ip>10.1.1.12</ip> <port>952</port> </parameters> </add> </dataSources> 为'true'的任何IP /端口进行端口连接测试。

我有以下功能,当我输入特定的<activeStatus>$hostname时,我已验证会给我正确的结果:

$port

所以现在我添加以下变量:

function Test-Port($hostname, $port) {
    # This works no matter in which form we get $host - hostname or ip address
    try {
        $ip = [System.Net.Dns]::GetHostAddresses($hostname) | 
              Select-Object IPAddressToString -ExpandProperty IPAddressToString
        if ($ip.GetType().Name -eq "Object[]") {
            #If we have several ip's for that address, let's take first one
            $ip = $ip[0]
        }
    } catch {
        Write-Host "Possibly $hostname is wrong hostname or IP"
        return
    }
    $t = New-Object Net.Sockets.TcpClient
    # We use Try\Catch to remove exception info from console if we can't connect
    try {
        $t.Connect($ip,$port)
    } catch {}

    if ($t.Connected) {
        $t.Close()
        $msg = "Port $port is operational"
    } else {
        $msg = "Port $port on $ip is closed, "
        $msg += "You may need to contact your IT team to open it. "                                 
    }
    Write-Host $msg
}

然后运行:

[xml]$DSConfig = gc "$DSConfigPath"

$DS = $dsconfig.datasources.add.parameters
$DSName = $DS.otherIdentifiers
$DSIP = $DS.ip
$DSPort = $DS.port
$DSActive = $DS | Where-Object {$_.activeStatus -eq 'True'}

$hostname = $DSIP   # yes I realize this is redundant
$port = $DSPORT     # and yes, I realize this is redundant as well

我得到了结果:

Possibly 10.1.1.10 10.1.1.11is wrong hostname or IP

有任何建议如何让它测试到10.1.1.10:952的连接,给出结果,然后测试连接到10.1.1.11:952然后给出结果?

3 个答案:

答案 0 :(得分:2)

使用mouseup从xml文档中获取onmouseup个节点:

SelectNodes()

答案 1 :(得分:0)

使用Select-Xml的替代方法。这实际上与Mathias的答案相同,但使用cmdlet而不是方法。除非您想要利用cmdlet中内置的一些其他选项(该方法不可用)(在这里不是很有用,但在更复杂的用途中肯定有用),但不是特别有用。

# Read XML document
[xml]$DSConfig = gc "$DSConfigPath"

# Select <parameters> nodes
$ParametersNode = Select-Xml -Xml $DSConfig -XPath '//parameters'|% {
    Test-Port $_.Node.ip $_.Node.port
}

答案 2 :(得分:0)

声明

$DS = $dsconfig.datasources.add.parameters

列出变量<parameter>中所有$DS个节点的列表。如果您检查$DS.Count,您会看到它的示例数据值为3,如果您回显变量,则会看到如下内容:

PS C:\> Write-Output $DS

name             :
address          : 10.1.1.10
otherIdentifiers : DataSource1
activeStatus     : true
ip               : 10.1.1.10
port             : 952

name             :
address          : 10.1.1.11
otherIdentifiers : DataSource2
activeStatus     : true
ip               : 10.1.1.11
port             : 952

name             :
address          : 10.1.1.12
otherIdentifiers : DataSource1
activeStatus     : false
ip               : 10.1.1.12
port             : 952

接下来的陈述

$DSIP = $DS.ip
$DSPort = $DS.port

将变量$DSIP$DSPort分别填入所有IP地址和所有端口的列表。

PS C:\> Write-Output $DSIP
10.1.1.10
10.1.1.11
10.1.1.12

在PowerShell v3和更新版本上,即。在PowerShell v3之前,语句会引发错误,因为较旧的版本不支持member enumeration,即当数组对象本身不支持时,访问数组的元素上的属性和方法。拥有该属性或方法。

当您将此IP地址列表传递给Test-Port时,语句

$ip = [System.Net.Dns]::GetHostAddresses($hostname)

MethodInvocationException失败,因为GetHostAddresses()需要单个字符串,而不是字符串数组。

另外,你的循环

foreach ($DSActive in $DSConfig) {Test-Port $hostname $port}

将在一次迭代后终止,因为$DSConfig只有一个元素:根节点(<dataSources>)。

要让代码为每个IP地址和端口调用Test-Path,请将上述循环更改为:

foreach ($DSActive in $DSConfig.datasources.add.parameters) {
    Test-Port $DSActive.ip $DSActive.port
}