Register for Semperis' Hybrid Identity Protection (HIP) Conference - June 30 - July 1 Register for Semperis' Hybrid Identity Protection (HIP) Conference - June 30 - July 1
PowerShell

PowerShell Problem Solver: Where is that IP?

In a previous PowerShell Problem Solver article, I used PowerShell to convert a ctime value to a proper datetime format. I had a list of IP addresses as part of the same troubleshooting process, and this is something you also might come across in a log file.

I wanted to be figure out where the IP address was coming from. For example, I might have an IPv4 address like this:

$ip = "54.215.12.190"

What is the IP address’ country of origin? Fortunately, I knew of a website that provides that information. Although I initially accessed this from the website, I wanted to access this information from PowerShell. To simplify this process, PowerShell 3.0 introduced a new cmdlet called New-WebServiceProxy. You can use the cmdlet to create a special type of object that acts as a proxy to the web service. You don’t have to figure out any arcane syntax to use the web service. Everything is exposed as an object that’s complete with method members. Let me show you.

First, I need to create the proxy object.

$px = New-WebServiceProxy "http://www.webservicex.net/geoipservice.asmx"

Most of the time the proxy properties don’t really matter.

Proxy properties in Windows PowerShell. (Image Credit: Jeff Hicks)
Proxy properties in Windows PowerShell. (Image Credit: Jeff Hicks)

What’s really interesting is what I can do with the proxy object. Pipe the object to Get-Member and discover its methods.

Piping our proxy object to Get-Member in Windows PowerShell. (Image Credit: Jeff Hicks)
Piping our proxy object to Get-Member in Windows PowerShell. (Image Credit: Jeff Hicks)

You might also need to read any documentation from the associated site about these methods. Instead of trying to construct a URL to invoke these methods, I can use PowerShell and the proxy object. Let’s look at the GetGeoIP method.

The GetGeoIP method in Windows PowerShell. (Image Credit: Jeff Hicks)
The GetGeoIP method in Windows PowerShell. (Image Credit: Jeff Hicks)

It looks like all I need to do is give it an IP address as a parameter. Let’s test.

$px.GetGeoIP($ip)
Providing an IP address as a parameter for GetGeoIP. (Image Credit: Jeff Hicks)
Providing an IP address as a parameter for GetGeoIP. (Image Credit: Jeff Hicks)

Well that was easy. I should also see what happens when this fails because eventually I’m going to want to use this in a function.

Invalid IP address error with GetGeoIP. (Image Credit: Jeff Hicks)
Invalid IP address error with GetGeoIP. (Image Credit: Jeff Hicks)

I’ll keep that in mind. In the meantime, I can try using the returned information to analyze some IP addresses that I have pulled from my log file.

$ips[0..10] | foreach { $px.GetGeoIP($_)} | Select IP,CountryName,CountryCode | Out-Gridview -title "GeoIP"

Errors were still written to the console, but I was able to successfully resolve a number of addresses. I only tested with a subset of addresses to prove this would work.

IP addresses that we've tested in GridView. (Image Credit: Jeff Hicks)
IP addresses that we’ve tested in GridView. (Image Credit: Jeff Hicks)

That is very useful. I could combine this with other PowerShell commands.

$data = $ips| foreach { $px.GetGeoIP($_)} | Select IP,CountryName,CountryCode 
$data | Group CountryName –noelement | Sort Count -descending

The other piece to the puzzle was that I wanted to know what company or organization owned particular IP address. In other words, I needed some way to do a WhoIs type lookup but from PowerShell.

It turns out this can also be done fromthe web. Instead of a web service, I need to invoke a Rest method using the services described here. This will require using another newer cmdlet called Invoke-RestMethod.

I will need to construct a URI using my test IP address.

$uri = "http://whois.arin.net/rest/ip/$IP"

Next, I can run it.

$r = invoke-restmethod -uri $uri

Most of the time, you’ll end up with an XML document that’s easy to traverse in PowerShell.

I probably need to drill down a bit further.

It looks like that address is part of a block that belongs to Amazon. Excellent. How about putting all of this together?

#requires -version 3.0

Function Get-GeoIP {
<#
.Synopsis
Get geographic location for a given IPv4 address.
.Description
This command will analyze an IPv4 address and show its related geographic location. You can also show the registered organization.
.Parameter IPAddress
An IPv4 address. This parameter has an alias of IP.
.Parameter WhoIs
Include registered organzation information.
.Example
PS C:\> get-geoip 54.215.12.190
IP                                     CountryName                            CountryCode
--                                     -----------                            -----------
54.215.12.190                          United States                          USA
.Example
PS C:\>  get-geoip 208.67.222.222 -WhoIs | format-list

IP              : 208.67.222.222
CountryName     : United States
CountryCode     : USA
RegisteredOwner : OpenDNS, LLC
.Notes
version: 2.0
updated: March 18, 2015

Learn more about PowerShell:
http://jdhitsolutions.com/blog/essential-powershell-resources/

  ****************************************************************
  * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
  * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *
  * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
  * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *
  ****************************************************************
.Link
Invoke-RestMethod
New-WebServiceProxy
#>

[cmdletbinding()]
Param(
 [Parameter(Position=0,Mandatory,
 HelpMessage="Enter an IPv4 address",
 ValueFromPipeline,ValueFromPipelineByPropertyName)]
 [ValidatePattern({\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}})]
 [Alias("IP")]
 [string[]]$IPAddress,
 [switch]$WhoIs
)

Begin {
    Write-Verbose -Message "Starting $($MyInvocation.Mycommand)" 

    #create a web service proxy
    Write-Verbose "Creating web service proxy"
    $px = New-WebServiceProxy "http://www.webservicex.net/geoipservice.asmx"

    #define a quick function to get WhoIs information
    Function Get-WhoIs {
    [cmdletbinding()]
    
    Param([string]$IP)
        Write-Verbose "Getting WhoIs org for $IP"
        $baseURL = 'http://whois.arin.net/rest'
        $uri = "$baseUrl/ip/$ip"
        Try {
            $r = Invoke-Restmethod $uri -ErrorAction Stop
            #write the registered org name to the pipeline
            $r.net.orgRef.name
        }
        Catch {
            Write-Warning $_.Exception.Message
        }
    } 
} #begin

Process {
    Foreach ($IP in $IPAddress) {
        Write-Verbose -Message "Processing $IP"
    
        Try {
            $r = $px.GetGeoIP($IP)
            #continue processing if the method was successful
            if ($r.returnCode) {
                $data = $r | Select IP,CountryName,CountryCode
                if ($WhoIs) {
                    #Add WhoIs information
                    $data | Add-Member -MemberType NoteProperty -Name RegisteredOwner -Value (Get-WhoIS $IP) -PassThru
                }
                else {
                    #write the data to the pipeline
                    $data
                }
            } #if returncode = 1
            else {
                Write-Warning "Failed to resolve IP $IP. $($r.ReturnCodeDetails)"
                #throw an exception so the Catch block will run
                Throw
            }
        } #Try
        Catch {
            #If there was an error running Invoke-RestMethod
            #create a custom object. 
            $data = [pscustomobject]@{
             IP = $IP
             CountryName = "Unknown"
             CountryCode = "UNK"
            }

            if ($WhoIs) {
                $data | Add-Member -MemberType NoteProperty -Name RegisteredOwner -Value $Null -PassThru
            }
            else {
                $data
            }

        } #catch
    } #foreach
} #process

End {
    Write-Verbose -Message "Ending $($MyInvocation.Mycommand)"
} #end

} #end Get-GeoIP


My Get-GeoIP function by default gets geographic information only.

But I added an optional WhoIs parameter that will include the associated organizational name. Instead of ignoring errors, I included error handling via Try/Catch so I don’t miss any IP addresses. Now I can process a log file like this, assuming the heading is IP or IPAddress.

$data = import-csv d:\temp\log.csv | select IP -unique | get-geoip –WhoIs

I can now analyze and filter all I want.

$data | sort CountryName,RegisteredOwner | format-table -GroupBy CountryName -Property IP,RegisteredOwner
Analyzing and filtering our data. (Image Credit: Jeff Hicks)
Analyzing and filtering our data. (Image Credit: Jeff Hicks)
$data | group RegisteredOwner -NoElement | sort Count -Descending | select -first 10
84 unresolved IP addresses. (Image Credit: Jeff Hicks)
84 unresolved IP addresses. (Image Credit: Jeff Hicks)

Looks like there were 84 addresses that I couldn’t resolve. But that’s my problem. The point is that PowerShell and a few web cmdlets made it easy to analyze raw data and put some meaning to it.

Related Topics:

BECOME A PETRI MEMBER:

Don't have a login but want to join the conversation? Sign up for a Petri Account

Register
Comments (0)

Leave a Reply

Register for the Hybrid Identity Protection (HIP) Europe Conference!

Hybrid Identity Protection (HIP) Europe 2021 - Virtual Conference

Mobile workforces, cloud applications, and digitalization are changing every aspect of the modern enterprise. And with radical transformation come new business risks. Hybrid Identity Protection (HIP) is the premier educational forum for identity-centric practitioners. At the inaugural HIP Europe, join your local IAM experts and Microsoft MVPs to learn all the latest from the Hybrid Identity world.