如何从 Foreach 循环中获取添加到集合中的 Powershell 对象的所有值?

How would I get all values of a Powershell Object added to a collection from a Foreach loop?

我有这个函数,它从 $interfaceIPs 获取 InterfaceIndex 并获得匹配的 NetRoute 数据,并将所有这些放在一个集合中。目前在终端上我有 3 个独立的活动 IPv4 地址,但是当我打印集合时,我只得到一个,与来自其各自 NetRoutes 的数据相匹配。

function Get-InterfaceRoutes {
    $collection = @()
    $interfaceIPs = Get-NetIPConfiguration | Select-Object -Property IPv4Address, InterfaceIndex

    Foreach ($interfaceIP in $interfaceIPs) {
        $route = Get-NetRoute -InterfaceIndex ($interfaceIP.InterfaceIndex) | Select-Object -Property ifINdex, DestinationPrefix, NextHop, RouteMetric, ifMetric
        $collection = [PSCustomObject]@{
            Index = ($interfaceIp.InterfaceIndex)
            Address = ($interfaceIP.IPv4Address)
            DestinationPrefix = ($route.DestinationPrefix)
            NextHop = ($route.NextHop)
        }
    }

    Write-Host  "Collection of items: " ($collection | Format-List | Out-String)
}

这是输出:

Collection of items:

Index : 16
Address : {169.254.71.100}
DestinationPrefix : {255.255.255.255/32, 224.0.0.0/4, ff00::/8, fe80::b0b4:b9b0:df22:4764/128...}
NextHop : {0.0.0.0, 0.0.0.0, ::, ::...}

我想让集合显示所有活动的 IP 地址,应该是 3,通过索引与其对应的 NetRoute 数据相匹配。

如果我离题太远并且有更简单的方法,请随时告诉我!

来自 Santiago Squarzon 的有用评论已经解释了基本问题,re-assignment 到变量 $collection

虽然在 PowerShell 中,大多数时候您不需要明确地创建和添加到数组,因为 PowerShell 在您捕获函数或函数的输出时自动创建数组声明成一个变量。这也更加 高效 因为每次使用 += 时 PowerShell 都必须 重新创建 一个数组(数组实际上是 固定大小!)。当 PowerShell 从捕获的输出自动创建一个数组时,它在后台使用 more efficient data structure

所以我会像这样修改函数:

function Get-InterfaceRoutes {
    $interfaceIPs = Get-NetIPConfiguration | Select-Object -Property IPv4Address, InterfaceIndex

    Foreach ($interfaceIP in $interfaceIPs) {
        $route = Get-NetRoute -InterfaceIndex ($interfaceIP.InterfaceIndex) | Select-Object -Property ifINdex, DestinationPrefix, NextHop, RouteMetric, ifMetric

        # Implicit output!
        [PSCustomObject]@{
            Index = ($interfaceIp.InterfaceIndex)
            Address = ($interfaceIP.IPv4Address)
            DestinationPrefix = ($route.DestinationPrefix)
            NextHop = ($route.NextHop)
        }
    }
}

请注意,我已将 $collection 变量全部删除!

相反,[PSCustomObject]@{} 是函数的隐式 输出。 PowerShell 将它写入 成功流,调用者可以从那里捕获它,或者只是让它通过以在控制台中显示它。

现在,当您真正想要 收集 该函数的输出到一个数组变量中时,您只需 将其赋值 给变量即可。

$routesArray = @(Get-InterfaceRoutes)

"Collection of items:" 
$routesArray | Format-List

@() array subexpression operator 确保您始终创建一个数组,即使该函数仅输出一个对象。


也就是说,有些情况下您实际上想要收集数组变量中的中间输出。假设您想将 foreach 的输出存储在局部变量中以供进一步处理。在这种情况下您仍然不需要显式创建数组,只需从 foreach 语句分配给变量:

# [array] is an alternative to @() for ensuring an array
[array] $collection = Foreach ($interfaceIP in $interfaceIPs) {
    $route = Get-NetRoute -InterfaceIndex ($interfaceIP.InterfaceIndex) | Select-Object -Property ifINdex, DestinationPrefix, NextHop, RouteMetric, ifMetric

    # Implicit output, will be captured and added to $collection
    [PSCustomObject]@{
        Index = ($interfaceIp.InterfaceIndex)
        Address = ($interfaceIP.IPv4Address)
        DestinationPrefix = ($route.DestinationPrefix)
        NextHop = ($route.NextHop)
    }
}

最后,如果你真的很想显式地创建一个数组(例如,当你需要从一个循环中添加到两个数组时),我建议使用 List class,这是对于重复添加,比原始数组更有效。此外,它还支持原始数组的所有操作,例如。 G。您可以使用索引运算符 [] 来访问其元素。

# Create an instance of List, with elements of type Object.
$collection = [Collections.Generic.List[Object]]::new() 

Foreach ($interfaceIP in $interfaceIPs) {
    $route = Get-NetRoute -InterfaceIndex ($interfaceIP.InterfaceIndex) | Select-Object -Property ifINdex, DestinationPrefix, NextHop, RouteMetric, ifMetric

    # Add a custom object to the list
    $collection.Add( [PSCustomObject]@{
        Index = ($interfaceIp.InterfaceIndex)
        Address = ($interfaceIP.IPv4Address)
        DestinationPrefix = ($route.DestinationPrefix)
        NextHop = ($route.NextHop)
    })
}