Network.psm1

#region Functions
#region Download-File
function Download-File()
{
    #Input Parameters
    Param(
        [string]$Source,
        [string]$destinationDirectory,
        [string]$destinationFilename,
        [Parameter(Mandatory=$false)] 
        [ValidateSet("IE11-Win8.1","IE11-Win8.1x64","Chrome35","Safari6","Firefox31")] 
        [string]$UserAgent="Chrome35"
)

    # Check if source is provided
    if( -not($Source) )
    {
        throw "You must specify a value for source."
        return
    }

    # Check if destination file name is provided
    if( -not($destinationFilename))
    {
        # Create a filename from URL
        $filename = $Source.substring($Source.lastindexof("/") + 1, $Source.length - $Source.lastindexof("/") - 1)
    }
    else
    {
        $filename = $destinationFilename
    }

    # Check if destination directory is provided
    if( -not ($destinationDirectory))
    {
        $destination = (resolve-path .).path + "\"
        $destination = (resolve-path .).path + "\" + $filename
    }
    else
    {
        if( -not(test-path $destinationdirectory))
        {
            throw "Destination Directory does not exist!"
            return
        }
        $destination = (resolve-path $destinationDirectory).path + "\" + $filename    
    }

    # Download file
    $wc = New-Object System.Net.WebClient
    $ua

    if( $UserAgent -eq "IE11-Win8.1" )
    {
        $ua = "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
    }
    if( $UserAgent -eq "IE11-Win8.1x64" )
    {
        $ua = "Mozilla/5.0 (Windows NT 6.3; Win64, x64; Trident/7.0; Touch; rv:11.0) like Gecko"
    }
    if( $UserAgent -eq "Chrome35" )
    {
        $ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1944.0 Safari/537.36"
    }
    if( $UserAgent -eq "Safari6" )
    {
        $ua = "Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25"
    }
    if( $UserAgent -eq "Firefox31" )
    {
        $ua = "Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0"
    } 

    $wc.Headers.Add("user-agent", $ua)
    $wc.DownloadFile($Source, $destination)
}
#endregion

#region Get-ExternalIP
function Get-ExternalIP 
{
    $wc=New-Object net.webclient
    $wc.downloadstring("http://checkip.dyndns.com") -replace "[^\d\.]"
}
#endregion

#region Get-MACAddress
function Get-MACAddress
{
    param($Target);
    $object = New-Object Object

    if( ($Target -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") -eq $true )
    {
        arp -d; # clear arp cache
        $ping = (new-object System.Net.NetworkInformation.Ping).Send($Target);
        $mac = arp -a;
        if($ping)
        {
            ($mac | ? {$_ -match $Target}) -match "([0-9A-F]{2}([:-][0-9A-F]{2}){5})" | out-null;
            Add-Member -memberType NoteProperty -name "IP Address" -value $Target -inputObject $object
            Add-Member -memberType NoteProperty -name "MAC Address" -value $matches[0] -inputObject $object
        }
    }
    else
    {
        $ip = [System.Net.Dns]::GetHostAddresses($Target) | where-object {$_.IPAddressToString -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" } | foreach {$_.IPAddressToString}

        arp -d; # clear arp cache
        $ping = (new-object System.Net.NetworkInformation.Ping).Send($ip);
        $mac = arp -a;              
        if($ping)
        {
            ($mac | ? {$_ -match $ip}) -match "([0-9A-F]{2}([:-][0-9A-F]{2}){5})" | out-null;
            Add-Member -memberType NoteProperty -name "IP Address" -value $ip -inputObject $object
            Add-Member -memberType NoteProperty -name "MAC Address" -value $matches[0] -inputObject $object
        }
    }
    $object
}
#endregion

#region Get-MACAddressWMI
function Get-MACAddressWMI
{
    Param
    (
        [string]$ComputerName = ".",
        [system.management.automation.psCredential]$Credential
    )

    if($Credential)
    {
        Get-WMIObject -Class win32_networkadapterconfiguration -ComputerName $ComputerName -Credential $Credential | Where-Object {$_.macaddress.length -gt 0} | Select-Object -Property Description, MACAddress | Format-Table
    }
    else
    {
        Get-WMIObject -Class win32_networkadapterconfiguration -ComputerName $ComputerName | Where-Object {$_.macaddress.length -gt 0} | Select-Object -Property Description, MACAddress | Format-Table
    }
}
#endregion

#region Ping-Host
function Ping-Host
{
    param([string]$HostName,[int32]$Requests = 3)
    
    for ($i = 1; $i -le $Requests; $i++) {
        $Result = Get-WmiObject -Class Win32_PingStatus -ComputerName . -Filter "Address='$HostName'"
        Start-Sleep -Seconds 1
        if ($Result.StatusCode -ne 0) {return $FALSE}
    }
    return $TRUE
}
#endregion

#region Get-NetAdapterIP
function Get-NetAdapterIP
{
    Param(
    )

    $items = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName .
    $results = @()

    foreach($i in $items)
    {
        $obj = New-Object PSObject
        $adaptername = (Get-NetAdapter -InterfaceDescription $i.Description).Name
        $obj | Add-Member -MemberType NoteProperty -Name Adapter -Value $adaptername
        $obj | Add-Member -MemberType NoteProperty -Name Address -Value $i.ipaddress
        $obj | Add-Member -MemberType NoteProperty -Name MACAddress -Value $i.macaddress
        $results += $obj
    }

    Write-Output $results
}
#endregion

#region Test-Port
Function Test-Port
{
    Param
    (
        [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('Server')]
        [string[]]$Computername,

        [Parameter(Mandatory = $true, Position = 1)]
        [int]$Port,

        [Parameter(Mandatory = $false, Position = 2)]
        [ValidateSet("TCP","UDP")]
        $Protocol = "TCP",

        [Parameter(Mandatory = $false)]
        $Timeout = 3
    )

    Begin {}

    Process
    {
        # Create the client
        $client = New-Object System.Net.Sockets.TcpClient

        foreach($c in $Computername)
        {
            # Create the custom object to return
            $result = New-Object psobject
            $result | Add-Member NoteProperty "Destination Hostname" $c

            # Get the IPs of the hostname from DNS
            try
            {
                $IPs = [System.Net.Dns]::GetHostAddresses($c) -join ","
                $result | Add-Member NoteProperty "Resolved IP" $IPs
            }
            catch
            {
                $result | Add-Member NoteProperty "Resolved IP" "Could Not Resolve"
            }

            # Create the timespan for the responce
            $date = Get-Date
            $timeToWait = New-TimeSpan -Start $date -End $date.AddSeconds($Timeout)

            if($Protocol -eq "TCP")
            {
                try
                {
                    # Try to connect
                    $connectionResult = $client.BeginConnect($c, $Port, $null, $null)
                    $success = $connectionResult.AsyncWaitHandle.WaitOne($timeToWait.Seconds)
                    if(!$success)
                    {
                        # Timeout
                        $result | Add-Member NoteProperty "Connected IP" $client.Client.RemoteEndPoint.Address
                        $result | Add-Member NoteProperty "Connected Port" $client.Client.RemoteEndPoint.Port
                        $result | Add-Member NoteProperty "Local IP" $client.Client.LocalEndPoint.Address
                        $result | Add-Member NoteProperty "Local Port" $client.Client.LocalEndPoint.Port
                        $result | Add-Member NoteProperty "Status" "Timeout"
                    }
                    else
                    {
                        $client.EndConnect($connectionResult)

                        # Add the IP that the client connected to and the status of the port to the custom object
                        $result | Add-Member NoteProperty "Connected IP" $client.Client.RemoteEndPoint.Address
                        $result | Add-Member NoteProperty "Connected Port" $client.Client.RemoteEndPoint.Port
                        $result | Add-Member NoteProperty "Local IP" $client.Client.LocalEndPoint.Address
                        $result | Add-Member NoteProperty "Local Port" $client.Client.LocalEndPoint.Port
                        $result | Add-Member NoteProperty "Status" "Listening"
                    }
                }
                catch [System.Net.Sockets.SocketException]
                {
                    # Add the "Connected IP" property and the status of the port
                    $result | Add-Member NoteProperty "Connected IP" $client.Client.RemoteEndPoint.Address
                    $result | Add-Member NoteProperty "Connected Port" $client.Client.RemoteEndPoint.Port
                    $result | Add-Member NoteProperty "Local IP" $client.Client.LocalEndPoint.Address
                    $result | Add-Member NoteProperty "Local Port" $client.Client.LocalEndPoint.Port
                    $result | Add-Member NoteProperty "Open" "Timeout"
                }
                finally
                {
                    # Close and dispose the client
                    $client.Close()
                    $client.Dispose()
                }
            }
            else
            {
                # Create the client
                $client = New-Object System.Net.Sockets.Udpclient(0)

                # Create a random message
                $encoder = new-object system.text.asciiencoding
                $message = $encoder.GetBytes("$(Get-Date)")

                try
                {
                    # Try to connect
                    $client.Connect($c,$port)
                    $result | Add-Member NoteProperty "Connected IP" $client.Client.RemoteEndPoint.Address
                    $result | Add-Member NoteProperty "Connected Port" $client.Client.RemoteEndPoint.Port
                    $result | Add-Member NoteProperty "Local IP" $client.Client.LocalEndPoint.Address
                    $result | Add-Member NoteProperty "Local Port" $client.Client.LocalEndPoint.Port

                    # Send and receive the test message
                    [void]$client.Send($message,$message.length)
                    $asyncResult = $client.BeginReceive($null,$null)
                    $asyncResult.AsyncWaitHandle.WaitOne($timeToWait) | Out-Null

                    if ($asyncResult.IsCompleted)
                    {
                        # Received a responce
                        $result | Add-Member NoteProperty "Status" "Listening"
                    }
                    else
                    {
                        # The timeout was reached
                        $result | Add-Member NoteProperty "Status" "Timeout"
                    }
                }
                catch [System.Net.Sockets.SocketException]
                {
                    # Add the "Connected IP" property and the status of the port
                    $result | Add-Member NoteProperty "Connected IP" $client.Client.RemoteEndPoint.Address
                    $result | Add-Member NoteProperty "Connected Port" $client.Client.RemoteEndPoint.Port
                    $result | Add-Member NoteProperty "Local IP" $client.Client.LocalEndPoint.Address
                    $result | Add-Member NoteProperty "Local Port" $client.Client.LocalEndPoint.Port
                    $result | Add-Member NoteProperty "Status" "Timeout"
                }
                finally
                {
                    # Close and dispose the client
                    $client.Close()
                    $client.Dispose()
                }
            }
            # Return the result
            $result
        }
    }

    End {}
}
#endregion

#region Get-IPInformation
function Get-IPInformation
{
    [CmdletBinding(PositionalBinding=$false)]
    [OutputType([String])]
    Param
    (
        [Parameter(Mandatory=$false, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [Alias("IPAddress")] 
        [string]
        $IP
    )

    Begin
    {
    }

    Process
    {
        # Check if an IP address has been provided
        if([string]::IsNullOrEmpty($IP))
        {
            # No IP provided, using current external IP
            Write-Warning "No IP provided, using current external IP."

            # Get the current external IP
            try
            {
                # Get the IP from ipinfo.io
                $response = Invoke-WebRequest -Uri "ipinfo.io/ip" -ErrorAction Stop -Verbose:$false
            }
            catch
            {
                Write-Error ("Failed to query information for IP " + $IP + ". " + $_.Exception.Message)
                return
            }

            # Configure the variable with the current IP
            $targetIP = $response.Content
        }
        else
        {
            # Configure the variable with the provided IP
            $targetIP = $IP;
        }

        # Form the request Uri
        $uri = "ipinfo.io/" + $targetIP + "/json"

        # Query for IP info
        try
        {
            $response = Invoke-WebRequest -Uri $uri -ErrorAction Stop -Verbose:$false
        }
        catch
        {
            Write-Error ("Failed to query information for IP " + $IP + ". " + $_.Exception.Message)
            return
        }

        # Output the IP information in a custom object
        $info = $response.Content |
            ConvertFrom-Json

        # Get the DNS server information (if any)
        try
        {
            $DNS = Resolve-DnsName -Name $IP -Type PTR -ErrorAction Stop -Verbose
            $DNS
        }
        catch
        {
            Write-Warning ("Failed to query DNS information for IP " + $IP + ". " + $_.Exception.Message)
        }

        # Create the custom object
        $properties = [ordered]@{
                        IP = $info.ip
                        City = $info.city
                        Region = $info.region
                        Country = $info.country
                        Location = $info.loc
                        Organization = $info.org
                        Timezone = $info.timezone
                        DNS = $DNS
                      }
        New-Object -TypeName PSObject `
                   -Property $properties
    }
    End
    {
    }
}
#endregion

#endregion

#region Aliases
New-Alias Get-IP Get-NetAdapterIP
#endregion