“Hey Irwin! Do you have a script to configure DNS autodiscover?” Eh, no not really… I’m assuming you’re doing something with PowerShell DNS cmdlets? 😉 And so begins another PowerShell journey…
My colleague Ofir is our Exchange guy.
“Ok so what exactly do you want to accomplish Ofir? I’m trying to automate registering some Resource records in DNS, but it isn’t working. I’d like to add some IPAddresses to a specific zone… “Ok let’s see what you’ve got!
Add-DnsServerResourceRecordA -Name "autodiscover" -ZoneName "domain.local" -AllowUpdateAny -IPv4Address "IP address 1","IP address 2","IP address 3" -TimeToLive 01:00:00
“So when I use the cmdlet directly it works. When I use varaiables it doesn’t… Ideally the code should be re-usable…” Â Ofir’s words not mine… I’ll admit, I teared up a bit… Kids, they grow up so fast… Hehe…
I think we can do this…
So Ofir was using read-host to get ZoneName and IPvAddress. Ah! What a lovely opportunity to demonstrate params!
“Ok Ofir, instead of using read-host, we’re better off using parameters. Using [CmdletBinding()] gives you the possibility to use Write-Verbose, no extra charge!”
[CmdletBinding()] Param( [string]$fqdn ='domain.local', [string[]]$ServerIPAddress )
Now because the Resource record could be multi-valued we’ll go on and define a string array variable [string[]]$ServerIPAddress
“To make you’re code more readable we’ll just go ahead and create a hashtable we can use to splat your parameters.”
$dnsSplat = @{ Name = 'AutoDiscover' Zonename = $fqdn AllowUpdateAny = $true IPv4Address = $ServerIPAddress TimeToLive = '01:00:00' }
“Now all we need to do it run the appropriate cmdlet and we’re good!”
Add-DNSServerResourceRecordA @dnsSplat
Ok, so this got Ofir started… Mind you there’s no error handling or anything of that sort…
We did some tinkering on the fly and this was the end result:
<# Author: I.C.A. Strachan Version: Version History: Purpose: Create AutoDiscover Zone and add ResourceRecord #> [CmdletBinding()] Param( [string]$fqdn ='domain.local', [string[]]$ServerIPAddress= @('192.168.1.4', '192.168.1.5') ) BEGIN{ $dnsRRA = @{ Name = 'AutoDiscover' Zonename = "autodiscover.$($fqdn)" AllowUpdateAny = $true TimeToLive = '01:00:00' } $dnsPZ = @{ Name = "autodiscover.$($fqdn)" ReplicationScope = 'Forest' DynamicUpdate = 'Secure' } Import-Module DNSServer -Verbose:$false } PROCESS{ #Only Add Zone is count is zero (doesn't exists) If (@(Get-DnsServerZone $dnsPZ.name -ErrorAction SilentlyContinue ).Count -eq 0 ){ Write-Verbose "Creating DNS Zone: $($dnsPZ.name)" Add-DnsServerPrimaryZone @dnsPZ } #Get string equivalent of all A records $RR = Get-DnsServerResourceRecord -ZoneName autodiscover.domain.local -RRType A | Out-String $ServerIPAddress | ForEach-Object { If (!$RR.Contains($_)){ Write-Verbose "Adding resource record $_ to $($dnsPZ.name)" Add-DNSServerResourceRecordA @dnsRRA -IPv4Address $_ } } } END{}
Ofir was quite happy! Nice! Another satisfied customer. So the other day asked him to send me the code for future reference…
This is what he sent me:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Author: I.C.A. Strachan / O. Doron | |
Version: 1.0 | |
Version History: | |
Purpose: Create AutoDiscover Zone and add ResourceRecord | |
Replace your local domain name and Mailbox server(s) IP address(es) with the | |
ones in the example: | |
Example: | |
.\Set-EX16DNSRecords.ps1 -fqdn domain.local -ServerIPAddress 192.168.1.4, 192.168.1.5 -verbose | |
#> | |
[CmdletBinding()] | |
Param( | |
[string]$fqdn ='domain.local', | |
[string[]]$ServerIPAddress= @('192.168.1.4', '192.168.1.5') | |
) | |
BEGIN{ | |
$dnsRRA = @{ | |
Name = '.' | |
Zonename = "autodiscover.$($fqdn)" | |
AllowUpdateAny = $true | |
TimeToLive = '01:00:00' | |
} | |
$mailRRA = @{ | |
Name = '.' | |
Zonename = "mail.$($fqdn)" | |
AllowUpdateAny = $true | |
TimeToLive = '01:00:00' | |
} | |
$webmailRRA = @{ | |
Name = '.' | |
Zonename = "webmail.$($fqdn)" | |
AllowUpdateAny = $true | |
TimeToLive = '01:00:00' | |
} | |
$srvRRA = @{ | |
Name = '.' | |
Zonename = "_autodiscover._tcp.$($fqdn)" | |
DomainName = "autodiscover.$($fqdn)" | |
priority = '0' | |
weight = '0' | |
port = '443' | |
AllowUpdateAny = $true | |
TimeToLive = '01:00:00' | |
} | |
$dnsPZ = @{ | |
Name = "autodiscover.$($fqdn)" | |
ReplicationScope = 'Forest' | |
DynamicUpdate = 'Secure' | |
} | |
$mailPZ = @{ | |
Name = "mail.$($fqdn)" | |
ReplicationScope = 'Forest' | |
DynamicUpdate = 'Secure' | |
} | |
$webmailPZ = @{ | |
Name = "webmail.$($fqdn)" | |
ReplicationScope = 'Forest' | |
DynamicUpdate = 'Secure' | |
} | |
$srvPZ = @{ | |
Name = "_autodiscover._tcp.$($fqdn)" | |
ReplicationScope = 'Forest' | |
DynamicUpdate = 'Secure' | |
} | |
Import-Module DNSServer –Verbose:$false | |
} | |
PROCESS{ | |
#Only Add Zone is count is zero (doesn't exists) | |
If (@(Get-DnsServerZone $dnsRRA.zonename –ErrorAction SilentlyContinue ).Count -eq 0 ){ | |
Write-Verbose "Creating DNS Zone: $($dnsPZ.name)" | |
Add-DnsServerPrimaryZone @dnsPZ | |
} | |
Else{ | |
Write-Verbose "DNS Zone $($dnsPZ.name) already exists" | |
} | |
If (@(Get-DnsServerZone $mailRRA.zonename –ErrorAction SilentlyContinue ).Count -eq 0 ){ | |
Write-Verbose "Creating DNS Zone: $($mailPZ.name)" | |
Add-DnsServerPrimaryZone @mailPZ | |
} | |
Else{ | |
Write-Verbose "DNS Zone $($mailPZ.name) already exists" | |
} | |
If (@(Get-DnsServerZone $webmailRRA.zonename –ErrorAction SilentlyContinue ).Count -eq 0 ){ | |
Write-Verbose "Creating DNS Zone: $($webmailPZ.name)" | |
Add-DnsServerPrimaryZone @webmailPZ | |
} | |
Else{ | |
Write-Verbose "DNS Zone $($webmailPZ.name) already exists" | |
} | |
If (@(Get-DnsServerZone $srvRRA.zonename –ErrorAction SilentlyContinue ).Count -eq 0 ){ | |
Write-Verbose "Creating DNS Zone: $($srvPZ.name)" | |
Add-DnsServerPrimaryZone @srvPZ | |
} | |
Else{ | |
Write-Verbose "DNS Zone $($srvPZ.name) already exists" | |
} | |
#Get string equivalent of all A records | |
$RRA = Get-DnsServerResourceRecord –ZoneName "autodiscover.$($fqdn)" –RRType A | Out-String | |
$RRB = Get-DnsServerResourceRecord –ZoneName "mail.$($fqdn)" –RRType A | Out-String | |
$RRC = Get-DnsServerResourceRecord –ZoneName "webmail.$($fqdn)" –RRType A | Out-String | |
$RRD = Get-DnsServerResourceRecord –ZoneName "_autodiscover._tcp.$($fqdn)" –RRType Srv | Out-String | |
$ServerIPAddress | ForEach-Object { | |
If (!$RRA.Contains($_)){ | |
Write-Verbose "Adding resource record $_ to $($dnsPZ.name)" | |
Add-DNSServerResourceRecordA @dnsRRA –IPv4Address $_ | |
} | |
Else{ | |
Write-Verbose "Resource record $_ exists in $($dnsPZ.name)" | |
} | |
If (!$RRB.Contains($_)){ | |
Write-Verbose "Adding resource record $_ to $($mailPZ.name)" | |
Add-DNSServerResourceRecordA @mailRRA –IPv4Address $_ | |
} | |
Else{ | |
Write-Verbose "Resource record $_ exists in $($mailPZ.name)" | |
} | |
If (!$RRC.Contains($_)){ | |
Write-Verbose "Adding resource record $_ to $($webmailPZ.name)" | |
Add-DNSServerResourceRecordA @webmailRRA –IPv4Address $_ | |
} | |
Else{ | |
Write-Verbose "Resource record $_ exists in $($webmailPZ.name)" | |
} | |
} | |
$srvRRA | ForEach-Object { | |
If (!$RRD.Contains($($srvRRA.DomainName))){ | |
Write-Verbose "Adding resource record $($srvRRA.DomainName) to $($srvPZ.name)" | |
Add-DNSServerResourceRecord –Srv @srvRRA | |
} | |
Else{ | |
Write-Verbose "Resource record $($srvRRA.DomainName) exists in $($srvPZ.name)" | |
} | |
} | |
} | |
END{} |
What??? This wasn’t the code I expected! Turns out Ofir had a lot more he needed to configure. Just pointing him in the right direction was sufficient to generate this! Awesome! Give a man a fish… 😉
Go Ofir! It’s fun to see colleagues get excited about PowerShell. Sometimes all that’s needed is just a nudge in the right direction…
Ttyl,
Urv
Pingback: Pester script to Test DNS Configuration | pshirwin