PowerShell在变量和文件上运行Select-String

时间:2015-03-13 06:28:57

标签: powershell pipeline select-string

我正在尝试使用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

但似乎没有任何效果。

我在哪里出错了?

谢谢!


更新03/13/2015下午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。最初的运行并没有为我返回任何东西,但我会玩弄它然后让你知道。

根据此更新信息,如果您对我的变量版本无法正常工作的原因有任何疑问,请告诉我。这对我来说完全不知所措。

再次感谢!


更新03/13/2015 10:27 pm

这是更新后$ 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中逐个运行Piped命令,会发生什么。正如你所看到的,它似乎突破了第14行:     $ ipAddress = $ ipAddress | %{$ _。匹配}

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

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>

2 个答案:

答案 0 :(得分:1)

链接Select-String

我认为这是你遇到的问题。那就是Select-StringWhere-Object一样。请考虑以下

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

这样的结果至少是一个IPv4字符串,因为完全是你要求的。了解select-string不返回字符串而是返回Microsoft.PowerShell.Commands.MatchInfo个对象。我可以想象通过你的头脑会发生什么事情"但我的输出应该是字符串?"。这就是为什么你看到Select-String使用% { $_.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-String的行为就像我已经提到过的Where条款一样。你也可以这样做:

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

其他方法

我发现非工作版没有任何问题,但我想提供一些改进select-string,因为你没有&#39 ; t确实需要使用多个稍微改变。

$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)

让我们尝试匹配的前三个八位字节,并制作一个转义匹配字符串。然后使用负向前瞻,我们匹配包含" 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地址。

答案 1 :(得分:0)

发现此行存在问题:

$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]

我应该注意,如果您返回了多个网络适配器,这可能不是最佳过程。在我的情况下,我有三个,这只选择最后一个。