Parse RegEx IP matches in Powershell array


Keywords:arrays 


Question: 

I am trying to work out how to parse an array for IP addresses. I have already worked out how to resolve the IP to DNS Hostname so far I have this:

Function Get-IP-Hostname
{
    Param([string[]]$array)

    $array.length

    foreach ($element in $array) 
    {
        $hname = [System.Net.Dns]::GetHostByAddress($element).HostName 

        $regex = "[regex] (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"

        @{$element = $hname}
     }
 } 

When I execute

Get-IP-Hostname 192.168.150.xx 192.168.151.xx  

with a bunch of IPs I have to use a comma to split, separate the string - my RegEx does not seem to split without a comma.

I am trying to get this output:

> Name                           Value                                  
> 
> ----                           -----                                                                                                                                                                                                                               
> 192.168.150.xx                 ank70dom07.akgroup.com                                                                                                                                                                                                             
> 192.168.151.xx                 ank70dom07.akgroup.com

I am pretty new to PowerShell and would appreciate any help.

Thanks!


4 Answers: 

Use [ValueFromRemainingArguments()] on your parameter if you want to be able to pass them in that way (as extra arguments).

Also there's a better way than regex to validate an IP address: just cast it as an [ipaddress].

function Get-IP-Hostname {
[CmdletBinding()]
param(
    [Parameter(ValueFromRemainingArguments = $true)]
    [String[]]
    $IPAddress
)

    foreach ($element in $IPAddress) {
        $ip = $element -as [Net.IPAddress]
        if ($ip) {
            @{$element = [Net.Dns]::GetHostByAddress($element).HostName}
        } else {
            # handle invalid IP (or don't)
        }
    }
}

You could simplify this even more by just making the parameter an array of ipaddresses ([ipaddress[]]), because the casting from strings will be done automatically:

function Get-IP-Hostname {
[CmdletBinding()]
param(
    [Parameter(ValueFromRemainingArguments = $true)]
    [IPAddress[]]
    $IPAddress
)

    foreach ($ip in $IPAddress) {
        @{$ip = [Net.Dns]::GetHostByAddress($ip.IPAddressToString).HostName}
    }
}

The snag here is that the entire call will fail if even one of the addresses passed in is not valid. So it depends on what you want to do.

One more suggestion: don't return a new hashtable with a single element each time. It looks right on the screen but it's not what you really want. You can fix it with a single hashtable, but I suggest something better: return an [IPAddress] object with an added HostName property:

function Get-IP-Hostname {
[CmdletBinding()]
param(
    [Parameter(ValueFromRemainingArguments = $true)]
    [String[]]
    $IPAddress
)

    foreach ($element in $IPAddress) {
        $ip = $element -as [Net.IPAddress]
        if ($ip) {
            $ip |
                Add-Member -NotePropertyName HostName -NotePropertyValue ([Net.Dns]::GetHostByAddress($ip.IPAddressToString).HostName) -PassThru
        } else {
            # handle invalid IP (or don't)
        }
    }
}

$results = Get-IP-Hostname 8.8.4.4 8.8.8.8

$results | fl * # all properties

$results | ft IPAddressToString,HostName # demonstrating what you want
 

Get rid of your $Array parameter and utilize the automatic variable $Args. It is already an array of all arguments received.

PS C:\> Function Get-HostnameFromIP { $Args }
PS C:\> Get-HostnameFromIP 134.222.659.0 148.398.388.299
134.222.659.0
148.398.388.299

The only hitch with this approach is you will need to cast the arguments to what you want them to be (strings) [Net.Dns]::GetHostByAddress("$Element")

Edit: Tested this approach and IPv4 addresses are interpreted as [String] in PSv5.1 already

 

You can use the -match parameter. E.g.

PS C:\> "192.168.0.1" -match "(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"  
True

If a match was found True is returned. You can retrieve the match result from the $Matches variable:

PS C:\> $Matches

Name                           Value                                                                                                                      
----                           -----                                                                                                                      
1                              192.168.0.1                                                                                                                
0                              192.168.0.1                                                                                                                

$Matches is an array (containing the regex match-groups) therefore you can retrieve a specific value via the []-operator

PS C:\> $Matches[1]
192.168.0.1  

You can also pipe multiple strings and check if one of them matches the regex:

PS C:\>"192.168.0.23", "10.0.0.1" | % { if ($_ -match "(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})") { $Matches[0]} }

You should also checkout this llink explaining -matches in more detail.

Hope that helps.

 

Use function "ResolveIPs" and use a RegEx formula to pull out only IP's, use ".matches" against the RegEx, then using "TRY" to resolve the hostname. Finally output results into an array.

function ResolveIPs {
    cls #clear console
    $regex = [regex] "\d{1,3}[.]\d{1,3}[.]\d{1,3}[.]\d{1,3}"
    $table = @() 

    foreach ($argument in $args){ 
        if ($argument -match $regex){ 
            $tempstr = $regex.Matches($argument) | %{ $_.value } 

            foreach ($value in $tempstr){
                $tablevalue = "" | select IP, Hostname 
                try {
                    $result = [Net.Dns]::GetHostByAddress($value).HostName

                    $tablevalue.IP = $value 
                    $tablevalue.Hostname = $result 
                    $table = $table + $tablevalue 
                }
                catch [exception] { 
                    $tablevalue.IP = $value 
                    $tablevalue.Hostname = "Error resolving IP address" 
                    $table = $table + $tablevalue
                }
            }  #endof foreach value
        }#end of IF
    }#endof foreach argument

    $table #output of table with results
}#end of function

You can now just import this script as a module (.psm1) and add any IP after the function "ReolveIPs".