Hey, Scripting Guy! I need to create several new zones in DNS, and I do not want to waste time working through the GUI wizard. I mean, real network administrators do not use wizards. In the old days, this was easy: I’d just edit a .dns file and I’d be done. But with Active Directory integrated stuff, I cannot figure out where the things are stored, how they are created, or anything. Do I really have to use that silly wizard?
– MT
Hi MT,
Wizards are great for people who are unsure of the different steps required to complete a task, for those activities that are rarely performed, or for things that are done only once. Real network administrators use whatever tool allows them to quickly, easily, and accurately perform the task at hand—wizard or not! But you are correct when you say that when you have a significant number of zones to create, the wizard can really slow you down. This is why we have the DNS WMI provider in the first place. It allows us to script these things. So to directly answer your question, you do not have to use the wizard if you do not want to do so.
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. |
To create a new DNS zone, we can use the MicrosoftDNS_Zone WMI class. An example of reading a CSV file and creating a number of DNS zones is seen in the New-DnsZone.ps1 script ((you will find a VBScript version of the script here):
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-DnsZone($DnsServer,$File) { Begin { Write-Host -ForeGroundColor Green "Creating new zones"} Process { Import-CSV $File | Foreach-Object { ([wmiclass]"\\$DnsServer\Root\MicrosoftDNS:MicrosoftDNS_Zone").` CreateZone($_.ZoneName,$_.ZoneType,$_.DsIntegrated,$_.DataFileName,[array]$_.IpAddr,$AdminEmailName) | Format-List -property RR } } } #end New-DnsZone # *** entry point to script *** $File = "C:\BestPracticesBook\DnsZones.csv" check-path $File $DnsServer = Get-DnsServer New-DnsZone -DnsServer $DnsServer -File $File
The first function we use is the Check-Path function. This function is used to check the path to the CSV file that holds our configuration information for the DNS zones. This is the same function we used yesterday.
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
The next function we use obtains the name of our DNS server for us. We do not have to use this function; we can override and point to a specific DNS server instead. This is the same function we introduced on Monday. Please refer there for more information about how this function works.
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
Okay, two functions down, and one to go. You might be asking yourself: What did the Scripting Guy actually write for today’s article? Dude! Talk about looking a gift horse in the mouth (We are doubly hurt as one of us is often called Mr. Ed.) To be totally transparent, we didn’t write diddly (but that is because he never returns my letters—we’ll be here all week, try the veal). We copied the first two functions, and modified the third function, and made one small change to the start of the script because we changed the name of the third function. Remember, the better designed the function is, the easier it is to re-use the code.
The New-DnsZone function was modified from the New-MxRecord function from yesterday’s “Hey, Scripting Guy!” article. We changed the description of the action in the Begin section of the function. We did not change either the Import-CSV section or the ForEach-Object section. This part of the code is seen here:
Function New-DnsZone($DnsServer,$File) { Begin { Write-Host -ForeGroundColor Green "Creating new zones"} Process { Import-CSV $File | Foreach-Object {
When we get to the method call, we need to change the name of the WMI class, the name of the method, and the method signature. We did not change the Format-List that the returned resource record is pipelined to. These are the major changes to the entire script. Let’s look at the CreateZone method from the MicrosoftDNS_Zone WMI class. This method is documented on MSDN. A breakdown of the method parameters is seen in Table 1.
Table 1 CreateZone method parameters | ||
Direction | Data Type | Name |
[in] |
string |
ZoneName |
[in] |
uint32 |
ZoneType |
[in] |
boolean |
DsIntegrated |
[in, optional] |
string |
DataFileName |
[in, optional] |
string |
IpAddr[] |
[in, optional] |
string |
AdminEmailName |
[out] |
MicrosoftDns_Zone |
RR |
We consider it a best practice to retain the names of the method parameters when creating values for the method. This makes it easy to move from the documentation to the script to the CSV file. The other advantage is you do not waste any time trying to create variable names, and you do not spend any cycles trying to recall what you named the variable later. Our CreateZone method call uses the automatic variable $_ to refer to the individual item on the pipeline. The item on the pipeline is the line from the CSV file seen here:
The hardest part of the script was getting the CSV file filled out properly. This is because different types of DNS zones need different values. Table 1 above mentions several optional parameters. However, these parameters are not optional for all of the different kinds of DNS zones. The error that is returned is not very helpful at all. It simply complains of a generic failure. When you look further, it tells you it was a MethodInvocationException, which means that there was a problem invoking the method. Um, duh! This error can be thrown if the zone already exists, if you try to boot from a DNS file and do not supply the file, if you try to create a primary DNS zone and set some other server authoritative, and in several other scenarios. In the following image, one DNS zone is created and two errors are thrown. The errors occur on the first and last line of the CSV file.
([wmiclass]"\\$DnsServer\Root\MicrosoftDNS:MicrosoftDNS_Zone").CreateZone` ($_.ZoneName,$_.ZoneType,$_.DsIntegrated,$_.DataFileName,[array]$_.IpAddr,$AdminEmailName) | Format-List -property RR } } } #end New-DnsZoneAfter the new DNS zones are created, you can see them in the DNS administration tool seen here:
But you can also just hop out to a Windows PowerShell console prompt and use the Get-WmiObject cmdlet to query the same class we just used to create the new DNS Zones. This is seen here:
PS C:\> Get-WmiObject -Class MicrosoftDNS_Zone ` -ComputerName berlin -Namespace root\microsoftDNS | Select-Object -Property Name Name ---- _msdcs.nwtraders.com nwtraders.com Resource1.NwTraders.com Resource2.NwTraders.com Resource3.NwTraders.com Resource4.NwTraders.com Resource5.NwTraders.com woodbridgebank.comThe entry point to the script is pretty much the same as the entry point to yesterday’s script. There are exactly two changes: the path to the file and the name of the function. These changes are seen here:
$File = "C:\ScriptingGuys\DnsZones.csv" check-path $File $DnsServer = Get-DnsServer New-DnsZone -DnsServer $DnsServer -File $FileWhen the script is run, the output shown in the following image is seen in the Windows PowerShell console:
Guess what, MT? We are done. That is it. This was a good example of code re-use, as well as working with the Microsoft DNS WMI provider. Join us tomorrow as DNS Week continues.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments