I'm trying to use a PowerShell script to extract my local network IP address from the output of ipconfig. I have gotten it working using a temporary output file but would like to eliminate that step and just use a variable inside the script. I cannot figure out why my script that isn't using a temporary output file won't work. Any help would be much appreciated.
Here are the two scripts. First, the working version:
$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
And now the almost identical, but non-working version using only variables:
$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
I am using select-string to find the lines containing 'IPv4' piped into another call to select-string to eliminate the line containing the IP address of my virtual machine. If I enable the test output on line 6 of the non-working script and compare it to the 'tmp.txt' file from the working script, I can see that up to this point, both scripts work identically.
Furthermore, lines 10-15 in both scripts are identical. So I believe that the only line in question is #8.
I have tried it every way I can think of, but always get the same result ("IPv4" rather than the IP address) The first script works as expected and gives me the IP.
Both of these options seem like they should work (and are probably the most logical of all that I've tried), but neither gives me the IP:
$ipAddress = select-string -inputObject $input -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }
and
$ipAddress = $input | select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }
I've even tried eliminating all the extra steps and just making one long pipe like this:
$ipAddress = ipconfig | select-string "IPv4" | select-string -notmatch "192.168.56." | select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }
and just copying to the clipboard like this:
ipconfig | select-string "IPv4" | select-string -notmatch "192.168.56." | select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value } | CLIP
But nothing seems to work.
Where have I gone wrong with this?
Thanks!
Updates 03/13/2015 6:30pm
I'm running Windows 7 64bit
Here's the output of $PSVersionTable:
Name Value
---- -----
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
And yes, my end goal is just to get the IP. Really, I just wanted to find a quick way to do that. I guess I didn't technically need the IP by itself for what I'm using it for, but then once I got into it, I got pretty caught up in trying to figure the rest of this out just out of curiosity.
Thanks for all the help!
I'm just getting back into coding after a ~10 year break and I'm super rusty.
I'm not sure why my non working version isn't working for me if it's working for you. When I run it, I get "IPv4" in the pop up and on the clipboard, rather than the IP (which I get in the working version that uses the temp file.
I'm going to integrate these regex changes to my current script and play around with your gwmi solution, Matt. An initial run isn't returning anything for me, but I'll toy around with it and let you know.
Let me know if you have any more ideas on why the version with the variable isn't working correctly on my end in light of this updated info. It's totally baffling to me.
Thanks again!
Updates 03/13/2015 10:27pm
Here's the output of $PSVersionTable after the update:
Name Value
---- -----
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
Here is what happens if I run the Piped Commands piece by piece in PowerShell. As you can see, it seems to break on line 14 at: $ipAddress = $ipAddress | % { $_.Matches }
Anyhow, thought this might help:
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>
Chaining Select-String
I think that is the issue you are having. That and you are treating Select-String
like Where-Object
. Consider the following
ipconfig | select-string "IPv4" | % { $_.Matches } | % { $_.Value }
The results of this would be at least one string that is IPv4 since that is exactly what you are asking for. Understand that select-string
does not return strings but Microsoft.PowerShell.Commands.MatchInfo
objects. I can imagine what is going on through your head would be "but my output should the strings?". That is why you see most uses of Select-String
use % { $_.Matches } | % { $_.Value }
to extract the matched strings.
There is a difference in what PowerShell is willing to show you on console and the actual underlying object. Not sure if you need more explanation. This edit would make your code work in place:
ipconfig | select-string "IPv4" | out-string |
select-string -notmatch "192.168.56." | out-string |
select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }
Still, that seems a little odd as the first Select-String
s are acting like Where
clauses like I already mentioned. You could also do this then:
ipconfig | Where-Object {$_ -match "IPv4" -and $_ -notmatch "192\.168\.56\." } |
select-string -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }
Other approaches
I don't see any issues with you non-working version but I would like to offer an improvement to you select-string
's since you don't exactly need to use more than one with some minor changes.
$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)
Lets take the first 3 octets that you are trying to not match and make an escaped matching string. Then using a negative lookahead we match the lines containing "IPv4" but that don't have the $ipAddressPrefix
following the colon.
Then, using all matches returned we split the string on the colon and space to get the IpAddresses matched. Again, note that it is very possible to get more than one address returned in this way.
Preferntial Method
Parsing string to get this information is fine and dandy but you can get it much easier using WMI and not having to working about things like leading and trailing spaces
$ipAddressPrefix = [regex]::Escape("169.254.125.")
$ipaddresses = gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress -and ($_.IPAddress -notmatch "$ipAddressPrefix|:") } |
Select -Expand IPAddress
$ipaddresses
should contain the same results using either code snippet. The Where
clause is broken down into these two parts
$_.IPAddress
--> this would filter out empty strings and nulls$_.IPAddress -notmatch "$ipAddressPrefix|:"
would ensure that the $ipAddressPrefix
matches are ommited. You will also see the :
which will omit the IPv6 addresses.