Sunday, 14 February 2016

Replicating cmd.exe behaviour in PowerShell for Ping / Tracert / Telnet



Reading this blog post (https://thinkpowershell.com/2016/02/use-test-netconnection-replace-ping/) recently got me thinking (not for the first time) about using more of the new PowerShell versions of the cmd.exe commands I use so frequently.

Then and in the past the two things that stop me are 1) after so many years, running ping is almost down to muscle memory, and 2) as diverse and powerful as they might be, the PowerShell versions aren't exactly known for their brevity!

My solution... spending the afternoon knocking together some functions which I can add to my profile, which replicate the syntax and produce similar if not better results than I normally get.

Ping

The first one's simple enough really :

function ping
{
    param(
        $PingAddress
    )
    Test-NetConnection -computername $PingAddress
}

Tracert

Trace route gets a bit more complex, not least because simply adding -TraceRoute to the Test-NetConnection command only returns the resulting IP addresses, but I generally want to know what they resolve to as well. As you'll see the required command gets a bit long if you want it to resolve the PTR records as well.

For added giggles, I also added a GeoIP lookup where the address is an IPv4 address as that's often handy to know.

function tracert
{
    param(
        $TracertAddress
    )
    # Where the address is an IP, do a GeoIP lookup as well
    If ($TracertAddress -match '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
    {
        # GeoIP Author: Patrick Lambert - http://dendory.net
        $geoip = New-WebServiceProxy -Uri "http://www.webservicex.net/geoipservice.asmx?wsdl" -Namespace WebServiceProxy
        $geoip.GetGeoIP($TracertAddress)
    }
    # The actual tracert part
    Test-NetConnection -ComputerName $TracertAddress -TraceRoute | `
        Select -ExpandProperty TraceRoute | `
        % { Resolve-DnsName $_ -type PTR -ErrorAction SilentlyContinue }
}

Telnet

The final one is Telnet, or specifically in my case seeing what is returned when a connection to a specified port is made. Note, you can do this using Test-NetConnection as well, however it only returns whether the connection is successful. If you're checking something like the responsiveness of an SMTP server, you also want to see the banner information returned as part of the request, which is why this script is a lot longer!

function telnet
# Based on http://myitpath.blogspot.co.uk/2013/02/simple-powershell-tcp-client-for.html
{
    param(
        [parameter(mandatory=$true,position=0,helpmessage="Hostname or IP")]
      [string]$hostname,
      [parameter(position=1)]
        $PortNum
    )

    if (test-connection $hostname) {
        $conn = new-object system.net.sockets.tcpclient($hostname,$PortNum)
        $str = $conn.getstream()
        $buff = new-object system.byte[] 1024
        $enc = new-object System.Text.ASCIIEncoding
        start-sleep -m 200
        $output = ""
        while ($str.DataAvailable -and $output -notmatch "username") {
            $read = $str.read($buff,0,1024)
            $output += $enc.getstring($buff, 0, $read)
            start-sleep -m 300
        }
        $conn.close()
        $output
    } else {
        Write-Error "Unable to ping or resolve host"
        exit 1
    }
}

So by adding those three to your PowerShell $profile (see http://www.howtogeek.com/50236/customizing-your-powershell-profile/ if you're unsure how) you can add those three old style commands to your PowerShell every time it loads.