Hey, Scripting Guy! Question

Hey, Scripting Guy! We are adding some new Exchange Servers to our messaging infrastructure, and I want to create some new MX (Mail Exchanger) records in DNS. I do not want to to create these records manually because carpal tunnel is not my friend and manual creation tends to introduce errors. I like having a text file that shows exactly what was created. Is this something that can be scripted?

- CI

SpacerHey, Scripting Guy! Answer

Hi CI,

Ding! Tea time. Be back in 15. Ah, sweet relief: Some gun powder green tea I brought back from my favorite shop in Munich, an ANZAC biscuit I scored during my last trip to Australia. I have to ration these things out because they are impossible to find in Charlotte, North Carolina, in the United States. Don't get me wrong; Charlotte is nice, but we don’t have a huge selection of Anzac biscuits. Around here, when you ask for a biscuit, they give you what looks more like a scone, and you are very likely to end up with gravy all over it. Sorry, CI. Another tangent. What was it you asked? Oh, yeah! You want to create some MX records via script. Can do. We will call our script New-MXRecord.ps1.

This week we are talking about DNS. For more information about DNS, you can refer to the Windows Server 2008 Networking and Network Access Protection (NAP) book in the Windows Server 2008 Resource Kit. There is also a chapter on scripting network services in the Windows PowerShell Scripting Guide. A number of good VBScript examples are in the Script Center Script Repository. The WMI DNS provider is documented here on MSDN.

A VBScript version of the New-MXRecord.ps1 script can be seen in the Script Center Script Repository. Without further ado, Here is New-MXRecord.ps1:

Function Check-Path($file)
{
 Begin { Write-Host -Foregroundcolor DarkCyan "Checking $file" }
 Process {
       If (-not(Test-Path -Path $file))
     {
      Throw "$file does not exist"
     }
 }
} #End Check-Path

Function Get-DnsServer
{
 Begin {Write-Host -ForeGroundColor Cyan "Obtaining local DNS Server information..."}
 Process {
  (Get-WmiObject -Class win32_networkadapterconfiguration`
    -filter "ipenabled =   $true").DnsServerSearchOrder[0]
 } #end Process
} #end Get-DnsServer

Function New-MXRecord($DnsServer,$File)
{
 Begin { Write-Host -ForeGroundColor Green "Creating MX records"}
 Process {
 Import-CSV $File |
 Foreach-Object {
([wmiclass]"\\$DnsServer\Root\MicrosoftDNS:MicrosoftDNS_MxType")`
.CreateInstanceFromPropertyData($_.DnsServer,$_.Container,$_.Owner,$_.RecordClass,`
$_.TTL,$_.Preference,$_.MailExchanger) |
Format-List -property RR
  }
 }
} #end New-MxRecord

# *** entry point to script ***
$File = "C:\ScriptingGuys\mxrecords.csv"
check-path $File
$DnsServer = Get-DnsServer
New-MxRecord -DnsServer $DnsServer -File $File

 If we were not able to use a script, we would be stuck mousing around the GUI DNS tool. This is fine for one record, but for more than that, it gets pretty boring very quickly. Here’s the GUI:

Image of the GUI

 

The first thing we do is check the path to the CSV file that holds our MX record information. This function is similar to the one we used to check the path for our Office Access database during Access Week. We update the function by adding a Begin block to print out a status message. We then use the Test-Path cmdlet to see if the file exists. If it does not exist, we use the Throw statement to raise an error. This is similar to the Err.Raise method from VBScript.

Function Check-Path($file
{
 Begin { Write-Host -Foregroundcolor DarkCyan "Checking $file" }
 Process {
       If (-not(Test-Path -Path $file))
     {
      Throw "$file does not exist"
     }
 }
} #End Check-Path

After we check for the existence of the CSV file, we need to find the information about the DNS server. This is the same function we used yesterday, and we will not discuss it today. Check out yesterday’s “Hey, Scripting Guy!” article for a detailed discussion of this function.

Function Get-DnsServer
{
 Begin {Write-Host -ForeGroundColor Cyan "Obtaining local DNS Server information..."}
 Process {
  (Get-WmiObject -Class win32_networkadapterconfiguration`
    -filter "ipenabled =   $true").DnsServerSearchOrder[0]
 } #end Process
} #end Get-DnsServer

Now we come to the New-MXRecord function. This function will be used to create the new MX Records in DNS. The function accepts two parameters: the first parameter is the DNS Server to connect to, and the second is the path to the CSV file that contains our MX record information. To create a function we use the Function keyword and give it a name. This is seen here:

Function New-MXRecord($DnsServer,$File){

Then we use the Begin parameter to print a progress message that tells the user we are creating the MX records. This is seen here:

Begin { Write-Host -ForeGroundColor Green "Creating MX records"}

Now we enter the Process section of the function. The first thing we do is use the Import-CSV cmdlet to import the CSV file.

Process {
Import-CSV $File |

We take the CSV content and feed it to the ForEach-Object cmdlet, which allows us to work with one line of data at a time as it comes across the pipeline. This is a very efficient arrangement because the CSV file could be huge otherwise. Rather than using up a lot of memory to store the contents of the CSV file in memory and spend all that time waiting for the entire contents of the file to be read from the file system, we are able to go to work on the CSV file as soon as the first line has been read.

ForEach-Object {

We use the WMIClass type accelerator to allow us to create a new MX record. It is efficient to work with this class directly. This is similar to using the Get method from the SwbemServices object like we did in VBScript days. In fact, you can compare this to the Create MX Record script. The [wmiclass] type accelerator takes the path to the MicrosoftDNS_MxType WMI class we want to use. It is on our remote DNS server, in the root\MicrosoftDNS WMI namespace, and the name is MicrosoftDNS_MxType. This part is seen here:

[wmiclass]\\$DnsServer\Root\MicrosoftDNS:MicrosoftDNS_MxType

The next thing we do is call the CreateInstanceFromPropertyData method. We give it the name of the DNS Server, the container in which to create the DNS record, the owner and class of the DNS record, the time to live value, a weighted preference, and the mail exchanger to use. These properties are all described on MSDN. All of the MicrosoftDNS_???Type WMI classes have a CreateInstanceFromPropertyData method. The method signature is similar between all of the WMI classes in this namespace, the only differences being peculiar to the individual DNS record type. This section of the code is seen here:

([wmiclass]"\\$DnsServer\Root\MicrosoftDNS:MicrosoftDNS_MxType")`
.CreateInstanceFromPropertyData($_.DnsServer,$_.Container,$_.Owner,`
$_.RecordClass,$_.TTL,$_.Preference,$_.MailExchanger) |

The CreateInstanceFromPropertyData method call returns an instance of MicrosoftDNS_RTType class. We display the information from that class by using the Format-List :

Format-List -property RR
  }
 }
} #end New-MxRecord

The formatted output from the Format-List cmdlet is seen here:

Image of the formatted output from the cmdlet

 

 

We now arrive at the entry point to the script. We assign the path to the CSV file, check the path to the file, obtain the DNS server information, and call the New-MxRecord functionfunction:

$File = "C:\ScriptingGuys\mxrecords.csv"
check-path $File
$DnsServer = Get-DnsServer
New-MxRecord -DnsServer $DnsServer -File $File

Woohoo! It's done. If you don't believe me, take a look in the MMC, as shown here:

Image of the MMC

Well, CI, that was cool. There is nothing more fun than writing a script that reads a CSV file and creates real live honest to goodness MX records in DNS. Certainly this is not something you will need to do every week, unless you are in consulting and you go around setting up DNS servers and doing a lot of Exchange work. But as I mentioned earlier in the article, the methodology is extremely similar amongst all the MicrosoftDNS record types. This means you can setup your DNS server from a script as easily as we created the three MX records—and that is pretty sweet. Speaking of sweet, join us again tomorrow as DNS week continues.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys