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

时间:2018-02-23 12:00:39

标签: powershell

我在Windows 10中使用一些简单的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是从服务器返回到列表的一系列IP地址,然后用于获取$ e。

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

$ r是路由表IPv4地址

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

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

2 个答案:

答案 0 :(得分:1)

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

$ix = [System.Net.Dns]::GetHostEntry($env:COMPUTERNAME).AddressList.IPAddressToString;

$e = If ($ix -ne $null) {
    $ix | ForEach-Object { ( $_.split('.')[0..1] -join '.') + '.' }
}   

$r = Get-NetRoute | Where-Object { $_.AddressFamily -eq 'IPv4' } | Select-Object -ExpandProperty 'DestinationPrefix'

$xline = ForEach ($f in $e) {
    $r -match $f
}

$xline

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

我还拿出了一个不必要的ForEach-Object,因为你可以做到它在前一个中所取得的成就。

以下是您的短格式修补程序:

$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

答案 1 :(得分:0)

使用一些背景信息补充Mark Wragg's helpful answer

  • 由于$r中的$r -match $e数组-match会执行过滤器:而不是返回布尔,与标量 LHS一样,$r中的匹配元素自身作为数组返回

    • 例如,@('aa', 'ab', 'bb') -match 'a'产生@('aa', 'ab')(而'aa' -match 'a' - 由于标量 LHS - 产生$True以表示成功匹配。< / LI>
    • 如果$r的元素没有匹配,则会得到数组(@()),这在许多PowerShell上下文中似乎是“空”结果或“没有” ”
  • 正如Mark指出的那样,在foreach ($v in $e) {$xline = $r -match $v}; write $xline循环中(我已使用$e替换迭代变量$v以避免混淆),您可以指定$xline 在每次迭代中而不是收集所有结果

    • 因此,您只使用返回的 last -match操作 - 这可能是也可能不是空数组,这将是解释断断续续的“不工作”。

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

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

这是一个简化(明确)迭代的简化解决方案(并且可能性能更好,但这不太重要):

# 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 $_ } }