2

我正在尝试使用 PowerShell 脚本从 ipconfig 的输出中提取我的本地网络 IP 地址。我已经使用临时输出文件让它工作,但想消除该步骤,只在脚本中使用一个变量。我无法弄清楚为什么不使用临时输出文件的脚本不起作用。任何帮助将非常感激。

这是两个脚本。首先,工作版本:

$input_path = 'C:\Users\Will\Code\Scripts\tmp.txt'
$regex = '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'

ipconfig | select-string "IPv4" | select-string -notmatch "192.168.56." > tmp.txt

$ipAddress = select-string -Path $input_path -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }

# Pop up an alert window with the IP address
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup($ipAddress,0,"Done",0x1)

# Copy the IP address to the clipboard
$ipAddress | CLIP

现在几乎相同但仅使用变量的非工作版本:

$regex = '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'

$input = ipconfig | select-string "IPv4" | select-string -notmatch "192.168.56."

#$input > inputVar.txt

$ipAddress = select-string -inputObject $input -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }

# Pop up an alert window with the IP address
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup($ipAddress,0,"Done",0x1)

# Copy the IP address to the clipboard
$ipAddress | CLIP

我正在使用 select-string 来查找包含“IPv4”的行,这些行通过管道传输到另一个对 select-string 的调用中,以消除包含我的虚拟机 IP 地址的行。如果我在非工作脚本的第 6 行启用测试输出并将其与工作脚本中的“tmp.txt”文件进行比较,我可以看到到目前为止,两个脚本的工作方式相同。

此外,两个脚本中的第 10-15 行是相同的。所以我相信唯一有问题的行是#8。

我已经尝试了所有我能想到的方法,但总是得到相同的结果(“IPv4”而不是 IP 地址) 第一个脚本按预期工作并给了我 IP。

这两个选项似乎都应该起作用(并且可能是我尝试过的所有选项中最合乎逻辑的),但都没有给我 IP:

$ipAddress = select-string -inputObject $input -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }

$ipAddress = $input | select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }

我什至尝试消除所有额外的步骤,只制作一个像这样的长管道:

$ipAddress = ipconfig | select-string "IPv4" | select-string -notmatch "192.168.56." | select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }

并像这样复制到剪贴板:

ipconfig | select-string "IPv4" | select-string -notmatch "192.168.56." | select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value } | CLIP

但似乎没有任何效果。

我在哪里做错了?

谢谢!


更新 2015 年 3 月 13 日下午 6:30

我正在运行 Windows 7 64 位

这是 $PSVersionTable 的输出:

名称 值
---- -----
CLRVersion 2.0.50727.5485
BuildVersion 6.1.7601.17514
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1

是的,我的最终目标只是获得 IP。真的,我只是想找到一种快速的方法来做到这一点。我想我在技术上并不需要 IP 本身来用于我使用它的目的,但是一旦我进入它,我就非常着迷于试图解决剩下的问题,只是出于好奇。

感谢所有的帮助!

在休息了大约 10 年之后,我才重新开始编码,而且我已经超级生疏了。

我不确定为什么我的非工作版本对我有用,如果它对你有用。当我运行它时,我在弹出窗口和剪贴板上得到“IPv4”,而不是IP(我在使用临时文件的工作版本中得到。

我将把这些正则表达式更改集成到我当前的脚本中,并使用你的 gwmi 解决方案,Matt。初始运行对我没有任何回报,但我会玩弄它并让你知道。

让我知道您是否有更多的想法,为什么根据这些更新的信息,带有变量的版本在我的端不能正常工作。这对我来说完全莫名其妙。

再次感谢!


更新 2015 年 3 月 13 日晚上 10:27

这是更新后 $PSVersionTable 的输出:

名称 值
---- -----
PSVersion 4.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion
4.0.30319.18444 BuildVersion 6.3.9600.16406
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion 2.2


如果我在 PowerShell 中逐段运行管道命令,会发生以下情况。如您所见,它似乎在第 14 行中断:$ipAddress = $ipAddress | % { $_.Matches }

无论如何,认为这可能会有所帮助:

PS C:\Users\Will\Code> $regex = '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'
PS C:\Users\Will\Code> $inputVar = ipconfig | select-string "IPv4" | select-string -notmatch "192\.168\.56\."
PS C:\Users\Will\Code> $inputVar

   IPv4 Address. . . . . . . . . . . : 192.168.0.105


PS C:\Users\Will\Code> $ipAddress = select-string -inputObject $inputVar -Pattern $regex -AllMatches
PS C:\Users\Will\Code> $ipAddress

   IPv4 Address. . . . . . . . . . . : 192.168.0.105


PS C:\Users\Will\Code> $ipAddress = $ipAddress | % { $_.Matches }
PS C:\Users\Will\Code> $ipAddress


Groups   : {IPv4}
Success  : True
Captures : {IPv4}
Index    : 3
Length   : 4
Value    : IPv4



PS C:\Users\Will\Code> $ipAddress = $ipAddress | % { $_.Value }
PS C:\Users\Will\Code> $ipAddress
IPv4
PS C:\Users\Will\Code>
4

2 回答 2

2

发现这一行有问题:

$input = ipconfig | select-string "IPv4" | select-string -notmatch "192.168.56."

您不能像在此处尝试使用 $input 那样使用它。它是 Powershell 中的默认变量之一。将 $input 的实例更改为 $iplist 或其他变量名称。

根据您的最新编辑更新答案:

奇怪的是看到它选择 IPv4。我在这里没有得到相同的结果。试试这个,它类似于 Matt 的方法,但跳过了几个 Foreach-Object 调用。

$ipAddress = (select-string -inputObject $inputVar -Pattern $regex -AllMatches).tostring().split(" ")[-1]

我应该注意,如果您返回多个网络适配器,这可能不是最好的过程。就我而言,我有三个,这只选择最后一个。

于 2015-03-13T22:31:19.777 回答
1

链接Select-String

我认为这就是你遇到的问题。那和你一样Select-String对待Where-Object。考虑以下

ipconfig |  select-string "IPv4" | % { $_.Matches } | % { $_.Value }

这样做的结果将是至少一个字符串是 IPv4,因为这正是您所要求的。了解它select-string不返回字符串而是Microsoft.PowerShell.Commands.MatchInfo对象。我可以想象你脑子里发生的事情是“但我的输出应该是字符串吗?”。这就是为什么您会看到大多数使用Select-Stringuse% { $_.Matches } | % { $_.Value }来提取匹配的字符串的原因。

PowerShell 愿意在控制台上向您显示的内容与实际的底层对象有所不同。不确定您是否需要更多解释。此编辑将使您的代码正常工作:

ipconfig |  select-string "IPv4" | out-string | 
    select-string -notmatch "192.168.56." | out-string |
    select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }

不过,这似乎有点奇怪,因为第一个Select-StringsWhere就像我已经提到的子句一样。你也可以这样做:

ipconfig | Where-Object {$_ -match "IPv4" -and $_ -notmatch "192\.168\.56\." } |
    select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }

其他方法

我没有看到你的非工作版本有任何问题,但我想对你select-string的版本进行改进,因为你并不需要使用多个小改动。

$ipAddressPrefix = [regex]::Escape("169.254.125.")
$ipaddresses = ipconfig | select-string "IPv4.*?: (?!$ipAddressPrefix).*" | % { $_.Matches } | % {$_.Value.Split(": ")[-1]}

# Pop up an alert window with the IP address
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup($ipaddresses,0,"Done",0x1)

让我们取您试图匹配的前 3 个八位字节并制作一个转义的匹配字符串。然后使用否定前瞻,我们匹配包含“IPv4”但没有$ipAddressPrefix以下冒号的行。

然后,使用返回的所有匹配项,我们拆分冒号和空格上的字符串,以获取匹配的 IpAddresses。再次注意,以这种方式返回多个地址是很可能的。

优先方法

解析字符串以获取此信息很好而且很花哨,但是您可以使用 WMI 更轻松地获得它,而不必处理诸如前导和尾随空格之类的事情

$ipAddressPrefix = [regex]::Escape("169.254.125.")
$ipaddresses = gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress -and ($_.IPAddress -notmatch "$ipAddressPrefix|:") } |
    Select -Expand IPAddress

$ipaddresses应该使用任一代码片段包含相同的结果。Where子句分为这两部分

  1. $_.IPAddress--> 这将过滤掉空字符串和空值
  2. $_.IPAddress -notmatch "$ipAddressPrefix|:"将确保$ipAddressPrefix省略匹配项。您还将看到:将省略 IPv6 地址。
于 2015-03-13T13:13:30.290 回答