Powershell ForEach循环间歇性工作-工作、失败、工作、失败、工作等

Powershell ForEach循环间歇性工作-工作、失败、工作、失败、工作等,powershell,Powershell,我对Windows10中一些简单的powershell代码有一个奇怪的问题。我想这可能是我做错了什么,但我不是一个powershell天才 我有这个: $ix = [System.Net.Dns]::GetHostEntry('<some server with a range of multiple IP addresses here>).AddressList.IPAddressToString; $e = If ($ix -ne $null) {$ix | % { $_.spl

我对Windows10中一些简单的powershell代码有一个奇怪的问题。我想这可能是我做错了什么,但我不是一个powershell天才

我有这个:

$ix = [System.Net.Dns]::GetHostEntry('<some server with a range of multiple IP addresses here>).AddressList.IPAddressToString;
$e = If ($ix -ne $null) {$ix | % { $_.split('.')[0..1] -join '.'} | % {$_ + '.'}}                         ; 
$r = Get-NetRoute | ? AddressFamily -eq 'IPv4' | Select -exp 'DestinationPrefix'; ForEach ($e in $e) {$xline = $r -match $e}; write $xline
$ix=[System.Net.Dns]::GetHostEntry(').AddressList.IPAddressToString;
$e=If($ix-ne$null){$ix |%{$|.split('..)[0..1]-join'.}{$|%{$|+'.};
$r=获取网络路由|?AddressFamily-eq'IPv4'|选择-exp'DestinationPrefix';ForEach($e in$e){$xline=$r-match$e};写$xline
$ix是从服务器返回到列表中的一系列IP地址,然后处理以获得$e

$e是从IP地址列表派生的每个IP地址的前两个八位字节的列表

$r是路由表IPv4地址

其目的是将$e中IP地址的前两个八位字节与$r中IP地址的前两个八位字节相匹配,然后使用$xline返回匹配的$r路由表IP地址。这项工作的预期,直到它不再

问题是它可以正常工作,然后突然不再工作,因为$xline变为空,即使$ix、$e和$r值仍然填充,并且它们的相关代码工作正常。几次尝试后,它将再次开始工作,再尝试几次,然后停止工作。我不知道我做错了什么,或者这是否是正确的方法,但我喜欢相对简单的方法。任何帮助都将不胜感激。多谢各位

试试这个(我重新格式化了代码,以便更清楚地进行故障排除):

主要的变化是将
$line
设置为
ForEach
循环中返回的所有值,而不是最后一个值

此外,我还为每个对象取出了一个不必要的
,因为您可以完成它在前面一个对象中实现的功能

以下是简短格式的修复程序:

$ix = [System.Net.Dns]::GetHostEntry('<some server with a range of multiple IP addresses here>').AddressList.IPAddressToString;
$e = If ($ix -ne $null) {$ix | % { ($_.split('.')[0..1] -join '.') + '.'}                        ; 
$r = Get-NetRoute | ? AddressFamily -eq 'IPv4' | Select -exp 'DestinationPrefix'; $xline = ForEach ($e in $e) { $r -match $e}; write $xline
$ix=[System.Net.Dns]::GetHostEntry(“”).AddressList.IPAddressToString;
$e=If($ix-ne$null){$ix |%{($..split('..)[0..1]-join'.)+'.};
$r=Get NetRoute |?AddressFamily-eq'IPv4'| Select-exp'DestinationPrefix';$xline=ForEach($e中的e){$r-match$e};write$xline
补充一些背景信息

  • 由于
    $r-match$e
    中的
    $r
    是一个数组,
    -match
    充当一个过滤器:与其像标量LHS那样返回布尔值,不如将
    $r
    中的匹配元素本身作为数组返回

    • 例如,
      @('aa','ab','bb')-匹配'a'
      产生
      @('aa','ab')
      (而
      'aa'-匹配'a'
      -由于标量LHS-产生
      $True
      ,表示匹配成功
    • 如果
      $r
      中没有匹配的元素,则会得到一个空数组(
      @()
      ),在许多PowerShell上下文中,该数组显示为“空”结果或“无”
  • 正如Mark指出的,在
    foreach($v in$e){$xline=$r-match$v};编写$xline
    循环(为了避免混淆,我用
    $v
    替换了迭代变量
    $e
    ),在每次迭代中分配给
    $xline
    ,而不是收集所有结果

    • 因此,您只使用最后一次
      -match
      操作返回的内容,该操作可能是空数组,也可能不是空数组,这将解释间歇性的“不工作”

    • 正如Mark的代码所暗示的,在
      foreach
      循环中根本不需要辅助变量,因为整个循环可以用作表达式,这意味着它的累积输出是按原样输出的(例如,可以在变量中捕获)

      • 因此,
        foreach($v in$e){$r-match$v}
        就是您所需要的

这里有一个简化的解决方案,它的迭代次数更少(明确),而且性能可能更好,尽管这在这里不太重要):


ForEach($e中的e)
ForEach($e中的f)你有什么建议吗?你知道我刚刚玩过它,它似乎很管用,读起来有点混乱。通常你会使用不同的变量(新的)名称。例如
ForEach($e中的f)
,然后在
ForEach
中使用
$f
。也就是说,这可能不是你的bug的原因。在
ForEach
中,虽然
$xline
被重复设置,所以只有循环的最后一次迭代才会代表它的值。你确定这是你想要的吗?Tbh我真的不明白你的code的作用是..它的
$ix
最终包含ipv6地址。
$ix = [System.Net.Dns]::GetHostEntry('<some server with a range of multiple IP addresses here>').AddressList.IPAddressToString;
$e = If ($ix -ne $null) {$ix | % { ($_.split('.')[0..1] -join '.') + '.'}                        ; 
$r = Get-NetRoute | ? AddressFamily -eq 'IPv4' | Select -exp 'DestinationPrefix'; $xline = ForEach ($e in $e) { $r -match $e}; write $xline
# Get all IPv4 destination prefixes.
# Note the use of @(...) around the command, which ensures that its output
# is treated as an *array* (which it most likely is anyway, in this case).
$ip4routeDests = @(Get-NetRoute | 
                    Where-Object AddressFamily -eq IPv4 |
                      Select-Object -ExpandProperty DestinationPrefix)

# Get the first 2 octets of all IPv4 addresses followed by a `*` to form
# a wildcard expression used with `switch` below.
# IPv4 addresses are identified by the presence of a `.` in them (`-match '\.')
# Regex '^(.+?\..+?\.).*' matches the entire input while extracting only 
# the first 2 octets; e.g., '172.16.'
$ip4addrWildcards =
  [System.Net.Dns]::GetHostEntry($env:COMPUTERNAME).AddressList.IPAddressToString `
    -match '\.' -replace '^(.+?\..+?\.).*', '$1*'                                                            #`

# `switch` allows us to implicitly loop over all wildcard patterns and match
# the destination prefixes against each with `-like`.
# This directly outputs all matches, but note that they'll be in the order
# implied by $ip4addrWildcards, i.e., the order in which the wildcards are specified.
switch ($ip4addrWildcards) { default { $ip4routeDests -like $_ } }