PowerShell for DDNS (DynDNS.org)
I’ll just leave this here. I realise many would prefer alternatives to using scheduled tasks such as Windows services or built-in methods from more advanced routers (as I do) but I had a need to write PowerShell to run every hour and update a DynDNS domain if the current IP doesn’t match the DNS IP.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
############# # VARIABLES # ############# # If you want to see what the script is doing, uncomment this. #$VerbosePreference = "Continue" # Servers to update - all are updated to the detected external IP of the machine running the script. $Servers = @("domain1.dyndns.org", "domain2.dyndns.org") # User agent string to send to DynDNS. $UserAgent = "lewisroberts.com - DynDNSUpdater (PoSh 5) - 1.0" # Get the credentials for the update. # Create yours using Get-Credential | Export-Clixml "DynDNS-$env:COMPUTERNAME.xml" $DynUP = Import-Clixml -Path "$PSScriptRoot\DynDNS-$env:COMPUTERNAME.xml" ############# # FUNCTIONS # ############# Function Get-ExternalIP(){ Try { $ExternalIP = Invoke-WebRequest -Uri "https://showextip.azurewebsites.net/" -Method Get -TimeoutSec 30 -UseBasicParsing } Catch { Return $false } $IPregex='(?<Address>(\b(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])\b))' If ($ExternalIP.Content -Match $IPregex) {Return $Matches.Address} Else {Return $false} } # Performs the DynDNS.org update if called to. Function Set-DynDNSUpdate { param([parameter(Mandatory=$true)][string] $HostAddress, [parameter(Mandatory=$true)][pscredential] $Credentials, [parameter(Mandatory=$true)][ipaddress] $IP ) Try { $Result = Invoke-RestMethod -Uri "https://members.dyndns.org/nic/update?hostname=$HostAddress&myip=$IP" ` -Credential $Credentials ` -UserAgent $UserAgent } Catch { Return $false } Return $Result } ############## # PROCESSING # ############## # Get the actual external IP address of this machine. $ActualIP = Get-ExternalIP If (!($ActualIP) -or ($ActualIP -eq $null)) { Write-Verbose "An error occurred getting the current IP. Quitting." Break } # For each host... Foreach ($DynDNSHost in $Servers) { Write-Verbose "Processing $DynDNSHost..." # Get the host's current DNS IP address Try { $DNSIP = [System.Net.Dns]::GetHostAddresses($DynDNSHost) | Select-Object -ExpandProperty IPAddressToString } Catch { Write-Verbose "Can't check the current IP so skipping host `"$DynDNSHost`"." Continue } # If the DNS lookup failed, report and continue to next host. If (!$DNSIP) {Write-Verbose "DNS lookup for `"$DynDNSHost`" returned nothing?"; Continue} # If the detected IP and current host DNS IP are not equal, an update is required. If ($ActualIP -ne $DNSIP) { Write-Verbose "[UPDATE] for $DynDNSHost to $ActualIP" # ...perform an update for this host $Result = Set-DynDNSUpdate -HostAddress $DynDNSHost -IP $ActualIP -Credentials $DynUP # If the response is not "good", output an error (only visible if verbose is on!) If (!($Result -match "good")) { Write-Verbose "[ERROR] An error occurred updating the IP address. Response from dyndns:`r`n$Result" } } # If the current external IP and the host DNS IP are the same, just say nothing happened. Else { Write-Verbose "[INFO] No update occurred.`t[ACTUAL]:$ActualIP [DNS]:$DNSIP" } } |
If you’re running this as a scheduled task, you must do it under the context of the same user that creates the credential file.
Hope it’s useful for you.
-Lewis
Hey lewis, this is exactly what I needed but I’m not familiar with powershell so I was wondering if I could pick your brain a bit. Especially the part where you are getting the credentials for the update. Not sure what to do about the .xml part.
Please e-mail me if you have time to discuss further.
Thanks
typed my e-mail incorrectly… duh!
Hi Jay, I appreciate PowerShell can be very daunting to a new user but fear not, it’s fairly simple.
The script itself is executed as a specific user on a specific computer so first experiment by simply opening the PowerShell console. You can use the Integrated Scripting Environment (ISE) or the console, but starting new, I would recommend you use the ISE.
At the prompt, type Get-Credential (uppercase or lowercase doesn’t matter) and press Enter. You’ll be prompted to enter a username and password. Type in anything you want (you’re testing) and press enter or click OK and you’ll see something appear on the command line with the username you entered and a value System.Security.SecureString. What you’ve done is created an “object”. Now, instead of sending that object to the console, you use the “pipe” (vertical character) to “pipe” the object to another command called Export-Clixml.
Do the same thing but this time type:
Enter your username and password (again, it can be anything at all, you’re only testing) and press Enter.
A file called mypassword.xml will be saved in to the path you are curently in – if you haven’t changed it since opening ISE, this will be C:\Users\[username]
Navigate to that path and you’ll see the file. Open it in Notepad and you’ll see your username and lots of other XML. The “password” you entered is encrypted and only readable by the user who created it.
Now, applying what you just learned, and using the commands from my script, execute:
In the prompt, enter the username and password you would use to log on to DynDNS and press Enter. A file called DynDNS-[The Name Of Your PC].xml will be created. Keep this XML file with the script (on the same PC you used when creating it!) and then run the script, not forgetting to update the host names you want to update with your current IP.
Hope that helps!
Great post, thank you for sharing. I needed a script to send my local IP (not internet-facing IP) to the service and this worked great with a few small tweaks.
Hey lewis, this is exactly what I need. But I keep getting “badauth” error everytime I send RestMethod, have double checked the username and password. If I copy the URL into a web browser it works fine.
Please e-mail me if you have time to discuss further.
Thanks
Hemant, you may need to provide your credentials in a specific format. For example if you’re using only a friendly user name, try using an email address instead or vice versa. There is a small possibility that Dyn have changed how you interact with their Rest endpoint but I’d be surprised if that were the case. It’s almost definitely just the username or password being incorrect.