Last Update: Sep 04, 2024 | Published: Jun 09, 2015
Today’s PowerShell Problem Solver focuses on a problem of my own. As you might imagine, running a blog is a time-consuming task, where I frequently run into performance or security problems that often leads me to downloading raw log files. Although processing this data can be tedious, PowerShell can help. One task I wanted is perform is to identify a website visitor’s IP address with the information I’ve obtained from my raw log files. This can easily done with PowerShell by accessing WhoIs information, which I’ll show you how to do in this article.
Although there are several websites that provide IP address information, I wasn’t about to manually copy and paste hundreds of IP addresses to get the information I needed. After a little research, I found a freely available web service that returns WhoIs information. These types of web services are intended for other websites and applications to consume, but you can just as easily use them in PowerShell. The arin.net website offers a number of free services. You have to take the time to read how to use them and figure out how to translate what you read into a PowerShell command. There’s no magic conversion, but hopefully with experience and examples like what I have for you today, this will become easier.
The service is exposed as a REST API. If you can find a service that uses the REST API, then you can use the Invoke-RestMethod cmdlet. That’s what we’re going to do here. The cmdlet needs address, which I’ll construct in PowerShell:
$baseURL = 'http://whois.arin.net/rest'
$ip = '208.67.222.222'
$url = "$baseUrl/ip/$ip"
Ready for how easy this is?
$r = Invoke-RestMethod $url
Very often the results come back as an XML document.
This lets you walk through the document easily.
The name property looks like it will be useful, which we can grab like this:
$r.net.name
We can also obtain multiple properties.
I can also keep drilling down. When I see a property name and a value of the same, this is probably another nested layer.
This name looks like it belongs to a corporation, which is useful. Look at the #text property. That is another URL and since it has ‘rest’ in the path, I bet it is another service I can query.
I already knew about this from reading the API documentation on the site, but even without that knowledge, it doesn’t cost me anything to try.
$s = Invoke-Restmethod $r.net.orgRef.'#text'
Because the XML node has a # in the name, I need to quote it. There were no errors, so what did I get?
Here’s another XML document that I can navigate and get some useful information. Excellent. Now that I have some core commands that work, I can build a re-usable function.
Function Get-MyWhoIs { <# .SYNOPSIS Get WhoIS data .DESCRIPTION Use this command to get public WhoIS domain information for a given IP v4 address. .PARAMETER Ip Enter an IPv4 Address. This command has aliases of: Address .PARAMETER Full Show complete whoIs information. .EXAMPLE PS C:> Get-MyWhoIs 208.67.222.222 OpenDNS, LLC .EXAMPLE PS C:> Get-MyWhoIs 208.67.222.222 -full IP : 208.67.222.222 Name : OPENDNS-NET-1 RegisteredOrganization : OpenDNS, LLC City : San Francisco StartAddress : 208.67.216.0 EndAddress : 208.67.223.255 NetBlocks : 208.67.216.0/21 Updated : 3/2/2012 8:03:18 AM .NOTES NAME : Get-MyWhoIs VERSION : 1.0 LAST UPDATED: 4/3/2015 AUTHOR : Jeff Hicks (@JeffHicks) Learn more about PowerShell:Essential PowerShell Learning 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 .INPUTS [string] .OUTPUTS [string] or [pscustomobject] #> [cmdletbinding()] Param ( [parameter(Position=0,Mandatory,HelpMessage="Enter an IPv4 Address.", ValueFromPipeline,ValueFromPipelineByPropertyName)] [Alias("Address")] [ValidatePattern("^d{1,3}.d{1,3}.d{1,3}.d{1,3}$")] [string]$IP, [Parameter(Helpmessage="Show complete WhoIs information.")] [switch]$Full ) Begin { Write-Verbose "Starting $($MyInvocation.Mycommand)" $baseURL = 'http://whois.arin.net/rest' #default is XML anyway $header = @{"Accept"="application/xml"} } #begin Process { $url = "$baseUrl/ip/$ip" $r = Invoke-Restmethod $url -Headers $header Write-verbose ($r.net | out-string) if ($Full) { $propHash=[ordered]@{ IP = $ip Name = $r.net.name RegisteredOrganization = $r.net.orgRef.name City = (Invoke-RestMethod $r.net.orgRef.'#text').org.city StartAddress = $r.net.startAddress EndAddress = $r.net.endAddress NetBlocks = $r.net.netBlocks.netBlock | foreach {"$($_.startaddress)/$($_.cidrLength)"} Updated = $r.net.updateDate -as [datetime] } [pscustomobject]$propHash } else { #write just the name $r.net.orgRef.Name } } #Process End { Write-Verbose "Ending $($MyInvocation.Mycommand)" } #end } #end Get-WhoIs
The Get-MyWhoIs function takes an IPv4 address as a parameter. By default, it only returns the name.
I also wrote the function so that I could pipe in an array of IP addresses.
My function will also get detailed information and drill down to the second link.
if ($Full) { $propHash=[ordered]@{ IP = $ip Name = $r.net.name RegisteredOrganization = $r.net.orgRef.name City = (Invoke-RestMethod $r.net.orgRef.'#text').org.city #<-- DRILL DOWN TO NEXT LEVEL StartAddress = $r.net.startAddress EndAddress = $r.net.endAddress NetBlocks = $r.net.netBlocks.netBlock | foreach {"$($_.startaddress)/$($_.cidrLength)"} Updated = $r.net.updateDate -as [datetime] } [pscustomobject]$propHash } else { #write just the name $r.net.orgRef.Name }
In PowerShell, this is a seamless experience and not much different than getting a service or process.
One last note on my function: I could have called it Get-WhoIs, but since “WhoIs” is practically an accepted standard term, I felt there might be a chance for a naming collision.
Instead, I simply added a My prefix to the noun. Some people and companies also use their initials. It doesn’t really matter. As long as some portion the noun is predictable, your command should be discoverable. I always tell people that when developing a PowerShell tool, you have to think about who will use it and what expectations they will bring to the table.
If you would like to learn more about scripting and toolmaking, consider getting a copy of Learn PowerShell Toolmaking in a Month of Lunches, 2nd. Ed.