Geocoding Longitude and Latitude using PowerShell and the Google Maps API

So, I ran into an issue where I needed to convert a ton of addresses to map points for use with a database.  It’s not something that I have to do too often, but I decided to look through the documentation for Bing, Google, OpenStreet, and MapQuest API’s.

After playing around with them all, it was just easier to use the Google API if I didn’t need to make too many calls at one time.  If I needed to make a bunch of calls (or I needed to make them repeatedly instead of just once), I would have went with Bing since it’s an easier API (IMHO).

I originally wrote this as part of a script, but then realized that it would work so much better as a function, so it was back to the drawing board and coding it as a function instead.  Overall, I’m pretty pleased with myself with how it works, but the true test is to have it out in the wild.  So without further ado, here’s the script.

<#
.Synopsis
   This function uses the Google Maps API to Geocode an address.
.DESCRIPTION
   This function uses the Google Maps API to Geocode an address by sending a web request to the API and then processes the resulting XML file for the longitude & latitude.  The Google API has a threshold and when violated, you get an OVER_QUERY_LIMIT error based on the number of calls made per second and per day.  If the function encounters this error it will pause for 2 seconds and throw a warning.  If two subsequent calls fail, then the daily max call may have been reached and it will error out.
.EXAMPLE
PS C:\> "7171 Southwest Parkway, Austin, TX" | Get-GeoCode

Address                                     Latitude                           Longitude                                                     
-------                                     --------                           ---------                                                     
7171 Southwest Parkway, Austin, TX          30.2510727                         -97.8631899 

.EXAMPLE
PS C:\> $Addresses = "Baltimore, MD", "Washington, DC"

PS C:\> $Addresses | Get-GeoCode

Address                                     Latitude                           Longitude                                                     
-------                                     --------                           ---------                                                     
Baltimore, MD                               39.2903848                         -76.6121893                                                   
Washington, DC                              38.9071923                         -77.0368707
#>
function Get-GeoCode
{
    [CmdletBinding()]
    Param
    (
        # Param1 help description
        [Parameter( Mandatory=$true,
                    ValueFromPipelineByPropertyName = $true,
                    ValueFromPipeline = $true,
                    Position = 0 )]
        [string]$Address
    )

    Begin
    {
        # Nothing
    }
    Process
    {
        $i = 0
        While ( $i -lt $Address.Count )
        {
            if ( $FailureCount -ge 2 )
            {
                Write-Error "You have called the Google Maps API too frequently and this has failed.  Wait 24 hours and try again."
                break
            }

            $Parameter = "address=" + $Address.Replace(" ","%20")
            $ApiUri = "https://maps.googleapis.com/maps/api/geocode/xml?$($Parameter)"
            $Response = Invoke-WebRequest -Uri $ApiUri
            $ResponseXml = [xml]($Response.Content)
            if ( $ResponseXml.GeocodeResponse.status -eq "OK" )
            {
                $ObjectHash = [ordered]@{ Address = $Address; Latitude = $ResponseXml.GeocodeResponse.result.geometry.location.lat; Longitude = $ResponseXml.GeocodeResponse.result.geometry.location.lng }
                New-Object -TypeName PSObject -Property $ObjectHash
                # It worked.  Move to the next element and reset the failure count
                $i++
                $FailureCount = 0
            }
            elseif ( $ResponseXml.GeocodeResponse.status -eq "OVER_QUERY_LIMIT" )
            {
                Write-Warning "Too many calls to the Google API.  Pausing for 2 seconds..."
                $FailureCount++
                Start-Sleep -Seconds 2
            }
            else
            {
                Write-Host "Failed to get GeoCode for '$Address' and continuing." -ForegroundColor Red
                $i++
            }
        }
    }
    End
    {
        # Nothing
    }
}

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.