Resolve-ASN.psm1

<#
.SYNOPSIS
This script takes as input hostnames or IP addresses, and returns information
on the autonomous system associated with the entity. It's a PowerShelly version
of whois.
 
.DESCRIPTION
This script takes a hostname, resolves it to an IP address, and attempts to
identify the autonomous system on the Internet responsible for that address. If an
IP address is provided, we us that directly. We return some basic information on the AS
like its advertising prefix, locale, and organization.
 
This script relies on the IP-to-ASN mapping service provided by Team Cymru,
which provides fairly good ASN data through DNS.
 
Proper whois would actually use a whois server and the whois protocol,
but its much easier to use a DNS service.
 
.PARAMETER HostName
The hostname used to gather ASN information.
 
.PARAMETER IPAddress
The IP address used to gather ASN information
 
.PARAMETER IPv4Only
This parameter indicates that ASN information should be returned only for IPv4 addresses. By default a random address for the host name is used.
 
.PARAMETER IPv6Only
This parameter indicates that ASN information should be returned only for IPv6 addresses.By default a random address for the host name is used.
 
.INPUTS
None
 
.OUTPUTS
The script outputs a System.Object for each AS that is declared as an owner
of the specified host.
 
.EXAMPLE
.\Resolve-ASN.ps1 bing.com
 
IPAddress : 65.52.107.149
ASNumber : 8075
ASPrefix : 65.52.104.0/21
Locale : US
Description : MICROSOFT-CORP---MSN-AS-BLOCK - Microsoft Corp
 
.EXAMPLE
Get-NetIPAddress -IPAddress 2001* | .\Resolve-ASN.ps1
IPAddress : 2001:4898:0:fff:200:5efe:157.59.25.188
ASNumber : 3598
ASPrefix : 2001:4898::/32
Locale : US
Description : MICROSOFT-CORP-AS - Microsoft Corp
 
.EXAMPLE
.\Resolve-ASN.ps1 xbox.com -IPv6Only
IPAddress : 2a01:111:f009::3b03
ASNumber : 8075
ASPrefix : 2a01:111::/32
Locale : GB
Description : MICROSOFT-CORP---MSN-AS-BLOCK - Microsoft Corp
 
 
.NOTES
Requires Windows 8 or later.
 
.LINK
The DNS service used for the script:
http://www.team-cymru.org/Services/ip-to-asn.html
The cmdlet that does all the hard work:
Resolve-DNSName
#>



function Resolve-ASN{

    param
                                                            (
        
    [Parameter(ParameterSetName="HostName",Mandatory=$True,
    ValueFromPipelineByPropertyName=$True , Position=0)]
    [string]$HostName = $null, 
    
    [Parameter(ParameterSetName="IPAddress", Mandatory=$True,
    ValueFromPipelineByPropertyName=$True)]
    [ipaddress]$IPAddress=$null,

    [Parameter(ParameterSetName="HostName", Mandatory=$false,
    ValueFromPipelineByPropertyName=$True)]
    [switch]$IPv4Only=$false,

    [Parameter(ParameterSetName="HostName", Mandatory=$false,
    ValueFromPipelineByPropertyName=$True)]
    [switch]$IPv6Only=$false
    )

    ##Services we're getting the ASN information from.
    $OriginService= ".origin.asn.cymru.com"
    $ASNService = ".asn.cymru.com"

    ##Convert the supplied hostname into a set of IP addresses.
    if($IPAddress -eq $null)
    {   
        write-debug "Hostname provided, will have to resolve to DNS name"
        try{
            if($IPv4Only)
                {$Records = Resolve-DnsName $HostName -Type  A -erroraction Stop}
            if($IPv6Only)
                {$Records = Resolve-DnsName $HostName -Type  AAAA -erroraction Stop}
            if(!($IPv4Only -or $IPv6Only))
                {$Records = Resolve-DnsName $HostName -Type  A_AAAA -erroraction Stop}

            }
        catch{
            throw "Could not resolve the provided hostname"
            exit
            }
        $Records = $Records | where {$_.IPAddress -ne $null}
    
        if ($Records -eq $null)
            {
                throw "No records found for the provided hostname"
                exit
            }
        else
            {
                $IPAddress = $Records[0].IPAddress
            }

             write-debug "Hostname resolved"

    }
            


    $IPAddressCasted = $null 

    ##Check if its an IPv6 Address. If so, we need to reverse the characters of the IP address
    if($IPAddress.AddressFamily -eq "InterNetworkV6")
    {
        $OriginService= "origin6.asn.cymru.com"
        $IPString = $IPAddress.IPAddressToString
    
        ##We're going to do some URI magic because it'll make our string conversions easier.
        $x = new-object -TypeName System.Uri -ArgumentList "http://[$IPString]"
        $ExpandedString = $x.DnsSafeHost
        $ExpandedString = $ExpandedString.ToCharArray()
        $ReversedString = ""
        foreach($character in $ExpandedString)
        {
            if($character -ne ":")
            {
                $ReversedString = $ReversedString.Insert(0,"$character.")
            }
        }
        $IPAddressCasted = $ReversedString 
        

    }
    else
    {
        ##Little bit easier to do reverse DNS lookups with IPv4
        if($IPAddressCasted -eq $null)
            {$IPAddressCasted = $IPAddress.ToString()}
    
        $Octets = $IPAddressCasted.Split(".")
        $Reversed = ""
        foreach ($Octet in $Octets)
        {
            $Reversed = "." + $Reversed.Insert(0,$Octet)
        }
        $IPAddressCasted = $Reversed.Substring(1)

    }
    ##Resolve the name against the ASN-IP service
    $NameToResolve = $IPAddressCasted + $OriginService
    try{
            write-Debug "START. Name to resolve against ASN-IP service"
            write-Debug $NameToResolve
            write-Debug "END."
            $DNSRecords = Resolve-DnsName $NameToResolve  -Type TXT -ErrorAction Stop
       }
        catch{
            throw "Could not find AS information for $NameToResolve"
            exit
        }


    ##Each record represent an ASN. We're going to populate more information on each object before returning them.
    ##This loop also generates the objects we'll be returning
    #foreach ($Record in $DNSRecords)
    #{
        
        $Record = $DNSRecords[0]
        write-Debug "START. Print the record."
        write-debug $Record
        write-Debug "END. Record is printed."
        $Result = New-Object System.Object
        $Result | Add-Member -Type NoteProperty -Name IPAddress -Value  $IPAddress
        Write-Debug -Message what 
        $Result | Add-Member -Type NoteProperty -Name ASNumber -Value $Record.Strings.Split("|")[0].Trim()
        $Result | Add-Member -Type NoteProperty -Name ASPrefix -Value $Record.Strings.Split("|")[1].Trim()
        $Result | Add-Member -Type NoteProperty -Name Locale -Value $Record.Strings.Split("|")[2].Trim()
        
        $NameToResolve = "AS" +$Result.ASNumber + $ASNService
        Write-Debug $NameToResolve
        try{
            
            $DNSRecord = Resolve-DnsName $NameToResolve  -Type TXT 
           }
        catch{
            throw "Could not resolve detailed infromation for AS" +$Result.ASNumber 
            exit
        }
        
        $Result | Add-Member -Type NoteProperty -Name Description -Value $DNSRecord.Strings.Split("|")[4].Trim()
        $Result
    #}

}


export-modulemember -function Resolve-ASN