Tag Archives: IP

Save External Dynamic IP to Dropbox

There are times when I’m away from the house, where I need to be able to reach my home computer via Remote Desktop. Because of this occasional need, I have my home router set up to allow this external connection. To do this required a static (internal) IP assignment for my home computer (I actually use a DHCP reservation), my router listening on port 3389 on the outside IP, and port forwarding that routes this external traffic to the home computer’s internal IP address. I used to connect by name, but the application I was using to sync my IP with my hostname, doesn’t seem to be working consistently. Therefore, I’ve been using my fallback option a lot lately: PowerShell and Dropbox.

Here’s what happens: I have a scheduled task on my home computer that runs a PowerShell script at 12 a.m., 6 a.m., 12 p.m, and 6 p.m. each day. The purpose of the script is to get my current, outside IP and write it, as well as the date and time, to a text file in Dropbox. That file is then snyced to my other computer and phone. It’s simple.

In line one, below, we create a variable, $UseableDate, to hold the string I use for the date and time. For today’s date, it might look something like this: D2015-08-19_T09-02-43-PM. This has long been my preferred way to store the date and time, especially when used in file names, as it will keep everything in a sort able order by year, month, and then day, and doesn’t include any invalid characters when used in a file path.

$UseableDate = Get-Date -Format 'Dyyyy-MM-dd_Thh-mm-ss-tt'

Next we need to collect the outside IP address. This is an important distinction — I don’t want my internal, NAT’d IP address. Line two, below, which checks in with dyndns.com, was borrowed from Aman Dhally. I’ve included a couple other options that can be used to populate the same $IPAddress variable (note: ifconfig.me has always seemed to be slower than the rest). Notice that using something other than dyndns will not require using any Regex, just some trimming to remove some white space surrounding the IP address.

$IPAddress = (Invoke-WebRequest -Uri ‘http://wtfismyip.com/text’).Content.Trim()
$IPAddress = (Invoke-WebRequest -Uri ‘http://ifconfig.me/ip’).Content.Trim()

$UseableDate = Get-Date -Format 'Dyyyy-MM-dd_Thh-mm-ss-tt'
$IPAddress = (Invoke-WebRequest -Uri 'http://checkip.dyndns.com').Content -replace "[^\d\.]"

The third line in the script, joins the date and time with the IP address and writes (appends) it to the file inside my Dropbox folder. Again, this is running from my home computer. Once in Dropbox at home, my work computer and phone will have the newest version of the file. In fact, it’s become a pretty good reminder that it is lunch time at work, as Dropbox pops up a Notification Area balloon that my file has been updated at 12 p.m.

$UseableDate = Get-Date -Format 'Dyyyy-MM-dd_Thh-mm-ss-tt'
$IPAddress = (Invoke-WebRequest -Uri 'http://checkip.dyndns.com').Content -replace "[^\d\.]"
"$UseableDate -- $IPaddress" | Out-File -FilePath 'C:\Users\tommymaynard\Dropbox\IP\homecomputer-IP.txt' -Append

To be as complete as possible, and save as many seconds as I can per day, I have a little function in my profile on my work computer to grab the IP address from the file. First, here’s an example of my homecomputer-IP.txt file (with hashtags taking the place of the digits):

...
D2015-08-18_T06-00-03-PM -- ##.###.##.###
D2015-08-19_T12-00-06-AM -- ##.###.##.###
D2015-08-19_T06-00-07-AM -- ##.###.##.###
D2015-08-19_T12-00-06-PM -- ##.###.##.###
D2015-08-19_T06-00-03-PM -- ##.###.##.###

The function below will extract the last IP address added to the homecomputer-IP.txt file. With that, I can add it to the Remote Desktop command line executable and get connected to the home computer from anywhere.

Function Get-HomeIP {
    $IPFile = 'C:\Users\tommymaynard\Dropbox\IP\homecomputer-IP.txt'
    (Get-Content -Path $IPFile | Select-Object -Last 1).Split(' -- ')[-1]
}
PS> Get-HomeIP
##.###.##.###
PS> mstsc.exe /v (Get-HomeIP)

That’s it — I hope this might be helpful to someone, someday. It’s saved me a time, or two now.

Update [02/09/2017]: I recently made a couple changes to the above function. The problem was that sometimes the IP wasn’t written to the file, for whatever reason. In this instance, my function ends up returning nothing. Therefore, I now sanitize the file first, so that any rows that don’t contain an IP address are excluded. Take a look.

Function Get-HomeIP {
    $IPFile = 'C:\Users\$env:USERNAME\Dropbox\IP\homecomputer-IP.txt'
    $SantizedIPs = Get-Content -Path $IPFile | Where-Object -FilterScript {$_.Length -gt 34}
    ($SantizedIPs | Select-Object -Last 1).Split(' -- ')[-1]
}

Finding Non-Resolveable IP Addresses

When preparing to bring new servers online, I often need a quick way to know what IP addresses, in a range of IP addresses, do not resolve to a name. This is the first step to determine unused IP addresses. The first time I did this was back before I was running Windows PowerShell 4.0 on Windows 8.1 which includes the Resolve-DnsName cmdlet. It meant I needed to use the command line tool nslookup; we’ll discuss both options in this post.

The first two examples below, use nslookup to try and resolve two different IPs: one that does resolve and one that doesn’t. It should be noted that resolving an IP address to a name is called Reverse DNS (rDNS). In the first example we have an IP address that resolves. That means it likely wouldn’t be an IP address I would want to use for a new server.

PS C:\> nslookup 10.10.10.2
Server:  dns.mydomain.com
Address:  10.10.10.1

Name:    dc01.mydomain.com
Address:  10.10.10.2

The next example shows an IP address that doesn’t resolve, and therefore, would likely be a useable IP address for one of my servers. Remember, we want to collect our failed name resolutions.

PS C:\> nslookup 10.10.10.4
Server:  dns.mydomain.com
Address:  10.10.10.1

*** dns.mydomain.com can't find 10.10.10.4: Non-existent domain

Let’s assume our range of possibly useable IPs is 10.10.10.2 – 10.10.10.254. This assumes we’re using .1 for the gateway and .255 for broadcast. We’ll use a sub range of this full range (10.10.10.2 through 10.10.10.5) for most of our testing and examples. We’re going to use the range operator (..) to help automate checking the IP addresses.

PS C:\> 2..5 | ForEach-Object {nslookup 10.10.10.$_}
Server:  dns.mydomain.com
Address:  10.10.10.1

Name:    dc01.mydomain.com
Address:  10.10.10.2

Server:  dns.mydomain.com
Address:  10.10.10.1

Name:    dc02.mydomain.com
Address:  10.10.10.3

Server:  dns.mydomain.com
Address:  10.10.10.1

*** dns.mydomain.com can't find 10.10.10.4: Non-existent domain
Server:  dns.mydomain.com
Address:  10.10.10.1

*** dns.mydomain.com can't find 10.10.10.5: Non-existent domain

Our results, above, indicate that .2 and .3 are resolving and therefore are likely not useable for us. It also indicates we may be able to use .4 and .5, since those are not resolving. There’s still too much information returned by nslookup, so let’s clean that up by only returning failed resolutions.

In the example below, we’ll pipe our nslookup results to the Select-String cmdlet and search for the three asterisks (***) that begin each line where there is a failed name resolution. By default, the Select-String cmdlet does a regex match, so we’ll need to use the more literal approach and include the -SimpleMatch parameter of Select-String.

PS C:\> 2..5 | ForEach-Object {nslookup 10.10.10.$_ | Select-String -Pattern *** -SimpleMatch}
*** dns.mydomain.com can't find 10.10.10.4: Non-existent domain
*** dns.mydomain.com can't find 10.10.10.5: Non-existent domain

PowerShell 3.0 on Windows 8 and Server 2012 brought us the Resolve-DnsName cmdlet as part of the DnsClient module. This is essentially the replacement for nslookup on newer versions of PowerShell, on newer versions of the underlying operating system. By default, this cmdlet will return much more information on a successful resolution and an error on a failed resolution. Although I’ve truncated the successful results, there is an example of both a success and failure, below.

PS C:\> Resolve-DnsName -Name 10.10.10.2

Name                       Type   TTL   Section    NameHost
----                       ----   ---   -------    --------
2.10.10.10.in-addr.arpa    PTR    214   Answer     dc01.mydomain.com
...

PS C:\> Resolve-DnsName -Name 10.10.10.4
Resolve-DnsName : 10.10.10.4 : The filename, directory name, or volume label syntax is incorrect
At line:1 char:1
+ Resolve-DnsName -Name 10.10.10.4
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (10.10.10.4:String) [Resolve-DnsName], Win32Exception
    + FullyQualifiedErrorId : ERROR_INVALID_NAME,Microsoft.DnsClient.Commands.ResolveDnsName

Now, what we need to do is find the failed name resolutions for our IP test range without displaying errors. This will require a little more work, but gives us more control over what’s actually displayed, instead of relying on the default output of nslookup.

In this example, we’ll run Resolve-DnsName for each IP address in our test range: 10.10.10.2 through 10.10.10.5. If it is unable to resolve, we’ll suppress the error using the -ErrorAction parameter, and then display our own message to inform us which IPs in our range didn’t resolve.

PS C:\> 2..5 | ForEach-Object {
>> If (-not(Resolve-DnsName -Name 10.10.10.$_ -ErrorAction SilentlyContinue)) {
>> Write-Output -Verbose "10.10.10.$_ -- Not Resolving"}
>> }
>>
10.10.10.4 -- Not Resolving
10.10.10.5 -- Not Resolving

If you made it all the way down here, then thanks for reading this post; I hope you found something useful. I would like to mention how to use .NET to resolve names to IPs, and IPs to names. Here’s a couple examples of both using a Microsoft name and IP.

PS C:\> [System.Net.Dns]::GetHostAddresses('microsoft.com')

Address            : 783919750
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 134.170.185.46

Address            : 3720129158
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 134.170.188.221

PS C:\> [System.Net.Dns]::GetHostByAddress('134.170.185.46')

HostName                                Aliases                                 AddressList
--------                                -------                                 -----------
grv.microsoft.com                       {}                                      {134.170.185.46}