As an IT guy, it’s very helpful for me to be able to remote to a machine outside of the current network in order to do testing — e.g., if the client is having weird DNS issues or routing issues, or if I’m doing work on a public facing web site.  I’ve got my home machine set up in such a manner that after jumping through a few hoops, I can remotely control it from wherever I am.

I don’t pay for a static IP address on a monthly basis, it seems pretty exorbitantly priced — my present ISP wants $15/mo for the privilege.  That said, I’ve been fairly lucky in that they don’t change my IP address much.  When they do, however, it messes up a few things — as I self-host this blog (among other things), the name server needs to be updated with the new IP address.  It used to be that you could use things like dyndns.org and the like, but at this point all of those have ceased being free, and I never liked the .dyndns.org suffix on any of the domain names anyways.

What I did to overcome this was write a small Powershell script that uses one of the public IP check websites, grabs the current IP, and if it has changed since the last time it grabbed it, sends it to me via e-mail.  The next incarnation may make use of my hosting provider’s API to automatically update the DNS entry, but I haven’t gotten that far yet.

I set this script to run as a scheduled task every 30 minutes and it has been serving me well now for over a year and a half, so I figured it may be helpful to someone else.  See below.  If there’s anything odd you feel I did and are curious about, drop a comment and I’ll explain.  Alternately, if there’s a better way to do anything I’ve done, I’d love to learn it — drop some knowledge in the comments section to help me out!

Two prerequisites — first being you must make a credential file and put it in the same directory that the script is executing from, and this file can *easily* be reversed by anyone who grabs a copy of the file.  As such, I don’t recommend using your primary personal e-mail account for this.  This is a pretty minor step, and you only have to do it once — here’s how you do it.  Run powershell and input the following commands:

"Your E-mail Password Goes Here" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "$pwd\credentials.txt"

Second prerequisite is that if you need to create the Event Log source that the script is going to write to — OR comment out the event logging portion of the script as it will throw errors if the log doesn’t exist.  The reason this isn’t in the script is that the script was written to run in non-elevated user context, and creating an event log requires an elevated session.  So, run the following from an elevated/administrator Powershell session to prepare your event log for the events or comment out with a # before each Write-EventLog line:

new-eventlog -source "IP Checker" -logname Application

Then, once you’ve gotten all of the pre-requisites completed, put your username, credential file location, and e-mail address info into the script below and you’ll be off to the races.

#Define credentials for e-mail later on
$username = "your_email_address@goes_here"
$password = cat $pwd\credentials.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password

#Remove username and password from memory as they are no longer needed and I'm paranoid.
Clear-Variable username
Clear-Variable password

#Get the old IP from the text file in this directory
$OLDIP = Get-Content $pwd\IP.txt -totalcount 1

#Provide a somewhat useful event to indicate whether the IP.txt was blank or not.
If (!$OLDIP) {
  Write-EventLog -Logname Application -Source "IP Checker" -EntryType Information -EventId 3001 -Message "IP Address not received from IP.txt.  Script will behave as though IP address has changed."
}

#Get the current IP from ifconfig.me
$NEWIP_DIRTY = (Invoke-WebRequest ifconfig.me/ip).Content

#If IP was not retrieved, sleep 180 seconds and retry repeatedly until an IP is retrieved.
If (!$NEWIP_DIRTY) {
  Do {
    Write-EventLog -Logname Application -Source "IP Checker" -EntryType Information -EventId 3001 -Message "IP Address not received from ifconfig.me/ip.  Sleeping for 180 seconds and trying again."
    Start-Sleep -s 180
    $NEWIP_DIRTY = (Invoke-WebRequest ifconfig.me/ip).Content
  } while(!$NEWIP_DIRTY)
}

#Remove the trailing newline character to sanitize the content of the variable for the upcoming test
$NEWIP = $NEWIP_DIRTY.TrimEnd("`n")

#Write information to Event Log for Tracking/troubleshooting
Write-EventLog -Logname Application -Source "IP Checker" -EntryType Information -EventId 3000 -Message "Retrieved old IP from IP.txt: $OLDIP`nCurrent IP after sanitization is: $NEWIP"

#If the IP has changed, e-mail it to me
If($NEWIP -ne $OLDIP) {
  Write-EventLog -Logname Application -Source "IP Checker" -EntryType Information -EventId 3999 -Message "IP flagged as having changed.  Previous IP: $OLDIP, Current IP: $NEWIP"
  Send-MailMessage -SmtpServer your.mailserver.com -Port 587 -To "target@email.address" -Subject "New IP Address!" -Body "IP Address has changed.  Previous IP: $OLDIP, current IP: $NEWIP" -From "from@email.address" -UseSsl -Credential $cred
  Out-File -filepath $pwd\IP.txt -InputObject $NEWIP
}