Manage your DNS records with PowerShell

In my video course PowerShell 5 Recipes, I used the Dnsimple API as an example of writing PowerShell modules. In the course, I uploaded and made the library available in the PowerShell gallery. Even though it is not feature-complete with respect to the DNSimple API, it is still usable for the core parts of the API.

Getting started

In order to access the Dnsimple API, you need an access token. In order to create one, log in to the web page and generate one under

https://dnsimple.com/a/<account id>/account/access_tokens

For simplicity going forward, create a PowerShell object to hold the account id and the access token:

$account = [pscustomobject]@{Account=27928;AccessToken=( convertto-securestring 'G2uiIZLhsHNWt4BFNq6Y8VnF1iRz2sB1' -asplaintext -for ce)}  Then, the next step is to install the module from the PowerShell Gallery, and load it into the current PowerShell instance: Find-Module DnsimplePS | Install-Module -Scope CurrentUser Import-Module DnsimplePS  In order to check the available cmdlets, list them: Get-Command -Module DnsimplePS Listing, adding and removing Zone records The simplest thing you can do, is to list the records for your domain: $account | Get-ZoneRecord -Zone kongs.li

You can also search for records of a certain type (case-sensitive):

$account | Get-ZoneRecord -Zone kongs.li -RecordType MX Or, you can get a certain record by name $account | Get-ZoneRecord -Zone kongs.li -Name www

Or, you can match records by prefix using -NameLike:

$account | Get-ZoneRecord -Zone kongs.li -NameLike w You can also add a record: $account | Add-ZoneRecord -Zone kongs.li -RecordType URL
-Name dnsimple -Content https://dnsimple.com/

And you can delete a record:

$account | Remove-ZoneRecord -Zone kongs.li -Id 11601106 Storing your access token securely In the getting started section above, I directed you to go to the DNSimple web page to get an access token. This is often not practical in automated scripts, so I provided a couple of cmdlets to store and retrieve an access token from a file, encrypted under the current user’s Windows credentials. So, when you have retrieved the token from the web page, you can store it securely like so: Write-AccessToken -AccessToken$t -Account 27928

This will create a file named .dnsimple.tokens next to your $PROFILE. The file will look something like this:  Deserialized.System.Collections.Hashtable Deserialized.System.Object 27928 01000000d08c9ddf0115d1118c7a00c04fc297eb01000000fff8656bc71ed747aa82e30ddd65735a00000000020000000000106600000001000020000000e7dfc8caf9534e51b2e2eb56b6968171ceb6c6ce9c8a7d55193791a207ffc56a000000000e800000000200002000000066c532a677f69c0c478733114d01b4371577340b0051160d95a3728d07c466ca500000005bbf59cee4314675324296591beeadef7970fc4e8589fce2b5bd80c6b5368e5198da424d1554a269921da4f0c6ef02e50db416fe2b7cbe63f187eb91d94d759da11e63121142f7e8794079e1ea74040d40000000d3f2a0be38aaa111ce20eeba05bcabb594e62400658486ed1c4ec2fe027e5d7e0916bc797aba0a0c1325fd7d0043ba9c9754782f695bdafab8a627f2259636f4  If you want to place the file somewhere else, point to it using the -Path parameter. Extra: URL-shortener In order to show off PowerShell modules being dependent on other modules, I created a second module that was dependent on the DnsimplePS module. This module has one cmdlet which is a short-hand for the special case I showed above for adding a record. It creates a URL type record, which is basically a redirect record that allows the creation of short urls. Example: $account | Add-ShortUrl -Zone kongs.li -Name dnsimple -Url https://dnsimple.com/

In the same vain, you can delete the url:

$account | Remove-ShortUrl -Zone kongs.li -Name dnsimple My PowerShell video course is available! For the last months, I have been working on my PowerShell 5 recipes video course. It is now finally published! Why? Why make a video course? – you might ask. I come from a system development background, having worked with many development platforms in my time (Java, .NET, Lotus Notes, JavaScript, etc.) Back in 2011, after resisted for a while, I decided to learn PowerShell. So I dived in, head first. Why? Because I realized that in order to get a better delivery process for software, we need a broader scope than just the development per se. We need to get a holistic view of the environment the applications will run in, and we need to automate the deployment. This has become more and more evident with the coming of DevOps and is key to continuous delivery. I am first and foremost a PowerShell user, and I do not consider myself an expert. Maybe a little more advanced than the average user, though. When the opportunity came to create a video course, the temptation to do something new to me as too hard to resist. I hope I have been able to keep the view of the user, resulting in a pragmatic, hands-on, course. For whom? The course is thought to be a smorgasbord of relevant topics in PowerShell that is relevant to the daily work of developers as well as IT. For people new to PowerShell, it will get you started by installing, and/or upgrading to the latest versions (even on Linux), customize, and set up the environment for your preferences. For developers, it gives you hands-on guidance to set up automated build and deployment. For DevOps (and IT), it guides you in provisioning Azure resources. For more advanced users, it gives you recipes on how to develop reusable scripts, handle modules and publishing your scripts to repositories. Enjoy! Installing Logstash on Windows using Scoop I just made Logstash available for installation on Windows through the brilliant command-line installer Scoop. This makes it very easy to install, upgrade or uninstall Logstash on your system. I earlier posted a similar instruction on how to install Logstash’s companion products Elasticsearch and Kibana in Windows in my employer’s blog. Here’s how you do it. If you haven’t already, install the command-line installer by running the following in Powershell: iex (new-object net.webclient).downloadstring('https://get.scoop.sh')  Then, add the extra definitions list (known as ‘buckets’ in Scoop): scoop add bucket extras That’s it for the installer part. Finally, install Logstash: scoop install logstash --global That’s it! To prove that the installation went well, run Logstash with a simple configuration: logstash -e 'input { stdin { } } output { stdout {} }'  You can then go on to install Logstash as a windows service, and start it logstash_service install -configPath path\to\logstash.conf logstash_service start Leet in PowerShell I am trying to be silly: Posh1337. Hello, Azure Scheduler The Scheduler is one of the new kids on the block in Azure Land. With Scheduler you can set up triggers for some sort of event in your system. It is currently in preview. I took some time to get to know the basics of it, and I wrote up a three part series of articles. You can find the articles in my company’s blog: PowerShell for developers: my talk on NDC Oslo 2013 On the Norwegian Developer’s Conference 2013 I gave a talk on PowerShell for developers. The video is now freely available: Powershell gotchas: refer to variables outside a function Consider the following code: $x = 1
function changeit {
"Changing $x. Was:$x"
$x = 2 "New value:$x"
}
"$x has value$x"
changeit
"$x has value$x"

Not too complicated, right. Let’s see what happens when we run it:

$x has value 1 Changing$x. Was: 1
New value: 2
$x has value 1 What’s going on? Well, trying to change the value of$x inside the function did not work. Why not? What the statement $x = 2 actually does, is to create a local variable inside the function and give it the value of 2. Let’s fix that: $x = 1
function changeit {
"Changing $x. Was:$x"
$script:x = 2 "New value:$x"
}
"$x has value$x"
changeit
"$x has value$x"

Now, we run it again:

$x has value 1 Changing$x. Was: 1
New value: 2
$x has value 2 The thing is that we have to explicitly tell Powershell to update the variable in the parent scope instead of creating a new variable in the current scope. Powershell gotchas: calling a function Consider the following code: function f($a, $b,$c) {
"f: $a=$a, $a.GetType()=$($a.GetType())" "f: $b=$b, $b.GetType()=$($b.GetType())"
"f: $c=$c, $c.GetType()=$($c.GetType())" } f 1 2 3 # call f with three integers as parameters f 1,2,3 # call f with an array of three integers f (1,2,3) # as above The gotcha here is not to fall into the trap to use a C#-like or Java(Script)-like syntax where parameters are separated by commas. The comma in Powershell is always an array constructor operator, and takes precedence over function application. (Which also means that adding paranthesis will yield the same result). The code above will result in: f:$a=1, $a.GetType()=int f:$b=2, $b.GetType()=int f:$c=3, $c.GetType()=int f:$a=1 2 3, $a.GetType()=System.Object[] You cannot call a method on a null-valued expression. At ...function-application.ps1:4 char:11 +$b.GetType <<<< ()
+ CategoryInfo          : InvalidOperation: (GetType:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
f: $b=,$b.GetType()=
You cannot call a method on a null-valued expression.
At ...function-application.ps1:5 char:11
+ $c.GetType <<<< () + CategoryInfo : InvalidOperation: (GetType:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull f:$c=, $c.GetType()= f:$a=1 2 3, $a.GetType()=System.Object[] You cannot call a method on a null-valued expression. At ...function-application.ps1:4 char:11 +$b.GetType <<<< ()
+ CategoryInfo          : InvalidOperation: (GetType:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
f: $b=,$b.GetType()=
You cannot call a method on a null-valued expression.
At ...function-application.ps1:5 char:11
+ $c.GetType <<<< () + CategoryInfo : InvalidOperation: (GetType:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull f:$c=, $c.GetType()= Powershell gotchas: xml.save needs an absolute path If given a relative path, xml.Save will do nothing, giving no error messages or anything. $xml = [xml]'<root><item>1</item></root>'
$xml.Save('.foo.xml') # Outputs nothing.$xml.Save((join-path (pwd) -ChildPath '.foo.xml')) # Actually writes


Powershell gotchas: standard out breaks lines to fit console

When Powershell writes to standard out, and there is now redirection in the Powershell script itself, it will assume that it writes to a console. Because of this, it kindly breaks lines if they are longer than 80 characters. So, given the following powershell file (.ps1):

# line-gunk.ps1
"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"

If you run this Powershell file from the Windows command line, and redirects output to a file:

C:>@powershell -file .line-gunk.ps1 > foo.txt

Then you will get:

1234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890



However, if you do the redirection in Powershell, it’s fine:

PS C:> .line-gunk.ps1 > bar.txt

A näive fix to this, would be to change your script to use Write-Host to explicity write the text to the console. However, I consider this a bad practice because it would restrict the usage of your script as you could not manipulate the output further if reusing the script. I found this entry on stackoverflow which provides a better solution. Going back to the original script, here is a fixed one that worked for me:

# line-gunk-fixed.ps1
\$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(500, 25)
"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"`

Notice that I used the simplifed version from the stackoverflow entry, which might not work in all circumstances.

Backstory

How did I come across this problem? I running Powershell build scripts in TeamCity and I was trying to report the build progress back to TeamCity. However, it somehow did not work. I then discovered that the status messages written by my script were broken by the line breaks, rendering them useless…