Complete DAG Creation via PowerShell

While working on a couple of other parts to this script (automating DAG member addition), I decided to write a script that allowed for a Point A to Point B build of an Exchange Server 2013 DAG. The requirements I used were relatively simple:

  • Create a File Share Witness
  • Create the DAG – FSW, name and IP assigned
  • Add a DNS record for the DAG on a DNS server
  • Add a computer object for the DAG
  • Add permissions for Exchange servers to the DAG computer object
  • Disabled the computer object

Seems like a short and easy list. However, it did take a few iterations to get the DNS sorted out and the permissions sorted out. I also used a PowerShell cmdlet that is new to me Add-DatabaseAvailabilityGroupServer, which adds computer accounts to the DAG.

Run this script on an Exchange Server, but make sure to use Windows PowerShell and NOT the Exchange Management Shell. If you do, the Add-AdPermission cmdlet will not work because the EMS uses the Exchange Trusted Subsystem in order to connect to AD, while Windows PS uses the current logged in account. EMS generates an error like this:

AccessRights

Above is the results of running this in the EMS. The blue circled results show what happens when the Exchange Trusted Subsystem does not have permissions on the DAG CNO. The green circled area is when the Exchange Trusted Subsystem has the correct rights and can add the permission to the DAG CNO. The only way to avoid this, since it is a manual step, is to run the script in Windows PS.

The Script

The script is a bit of coding I’ve found from Microsoft along with my own customizations and features – computer object creation, DNS entry added and security applied to the CNO for the DAG.

CLS
write-host " "
write-host "Do you want to (1) create or (2) remove a DAG? " -ForegroundColor Green -NoNewline
$dagchoice = read-host 

if ($dagchoice -eq "1") {
    CreateDAG
}
if ($dagchoice -eq "2") {
    DeleteDAG
}

This section, while at the bottom of the script, is the beginning of the script. First a question is asked, do you want to create or delete a DAG. The Create a DAG function will run a function called CreateDAG. The DeleteDAG function that is called by option ‘2’ will walk through the process of removing the servers from the DAG, removing the DNS entry for the CNO, remove the CNO and remove the DAG from Exchange Server as well.

CreateDAG Function

$DagName = Read-Host "Enter the name for the DAG:"
$DAGip = Read-Host "Enter the ip/ips for the DAG:"
$FSW = Read-host "Enter the name of a server to be used for a FSW"
$FSWDir = read-host "Please enter the file directory for the FSW share on $FSW"
write-host " "
write-host "Please verify you have added permissions for a non-Exchange server to be the FSW for Exchange 2013" -ForegroundColor Green
write-host " "

The above section is used for gathering information on the DAG creation – name, FSW, FSW directory and DAG IP address.

#If Multiple ips below variable will be used
$IPSplit = $DAGip.Split(',;')
$Search = New-Object DirectoryServices.DirectorySearcher([ADSI]“”)
$Search.filter = “(&(objectClass=Computer)(name=$DagName))”
$A=$Search.Findall()

 if ($A[0].path -ilike "*$DagName*") {
    Write-Host "DAG name $DagName Already Exist in AD, select a DAG Name that does not exist in AD and re-run the script"
 }

This section handles the option of multiple IP Addresses as well as looks for a duplicate name for the DAG in AD. If there is a duplicate, the script exits.

Else {
    Write-Host "Creating DAG $Dagname ........"

    $New = New-DatabaseAvailabilityGroup -Name $DAGName -WitnessDirectory $FSWDir -WitnessServer $FSW
    
    Write-Host "Fileshare witness is created on $FSW and Fileshare Witness located at $FSWDir"
    Write-Host "Sleeping for 20 seconds to replicate" ; start-sleep -seconds 20

This section handles adding one or more IP addresses to the DAG:

 if ($New.name -ilike "$DagName") {
        Write-Host "$DagName is created successfully, Setting up the Static Ip addresses."
        
        #Condition to check if its single or multiple ips
        if ($Dagip -ilike "*,*")  {
            Set-DatabaseAvailabilityGroup -Identity $Dagname -DatabaseAvailabilityGroupIpAddresses ($IPSplit[0]),($IPSplit[1]) 
            if ($? -eq $False){$Status = "FAILED"}
            else { $Status = "SUCCESS"}
            write-Host "$Status - Set ip address $DAGip to DAG $Dagname"
            if ($Status -eq "FAILED"){writelog $error[0]}
            start-sleep -seconds 15
            Get-DatabaseAvailabilityGroup $Dagname |fl
        } Else {
            Set-DatabaseAvailabilityGroup -Identity $Dagname -DatabaseAvailabilityGroupIpAddresses $DAGip
            if ($? -eq $False){$Status = "FAILED"}
            else{$Status = "SUCCESS"}
            write-Host "$Status - Set ip address $DAGip to DAG $Dagname"
            if ($Status -eq "FAILED"){writelog $error[0]}
            start-sleep -seconds 30
            Get-DatabaseAvailabilityGroup $Dagname |fl

This section will create the CNO in AD, disables the object per Microsoft and then gets the distinguished name for later use:

# Create Computer account, assign permissions, disable the object
    New-ADcomputer –name $dagname –SamAccountName $dagname
    Get-ADComputer cu7dag |set-adcomputer -enabled $false
    $dn=(get-adcomputer $dagname).distinguishedname

This section of code installed the DNS Server Tool Windows feature, adds a DNs entry for the DAG, validates it and then removed the DNS Server Tool Windows feature:

# Add DNS Record
            write-host "Now the script will add a DNS Record for the $dagname DAG." -ForegroundColor Yellow;write-host " ";write-host "Installing DNS Server Tool Feature" -ForegroundColor red;write-host " "
        
        # Check if DNS Module is available, if not, add it
            $installed = (Get-WindowsFeature rsat-dns-server).installstate
            if ($instaled -ne "Installed") {Add-WindowsFeature rsat-dns-server}
            import-module dnsserver
            write-host " ";write-host "Specify a DNS Server Name or IP Address " -NoNewline -ForegroundColor Green;$server = read-host
            $dnsroot = (get-addomain).dnsroot
            Add-DnsServerResourceRecordA -Name $dagname -ZoneName $dnsroot -AllowUpdateAny -IPv4Address $DAGip -TimeToLive 01:00:00 -ComputerName $server
            write-host "Validating the record was added:" -ForegroundColor white
            Get-DnsServerResourceRecord -name $dagname -zonename $dnsroot -computername $server |ft
        
        # Remove the DNS Module
            write-host "Removing DNS Server Tool Feature" -ForegroundColor red
            Get-WindowsFeature rsat-dns-server | Remove-WindowsFeature

This final section adds the computer accounts to the DAG’s CNO with full control as per Microsoft:

# Add computers to DAG
            write-host " ";write-host "Do you want to add (1) All mailbox server to the $dagname DAG or (2) Just some servers?" -nonewline -ForegroundColor Green;write-host " "
            $dagmembers = read-host

        # Add security so the script can continue its progress
            write-host" ";write-host "If using Windows PowerShell, ignore the below error.  If you are using the Exchange Management Shell, you need to follow the steps below:" -ForegroundColor yellow;write-host " "
            write-host "MANUAL STEP" -NoNewline -ForegroundColor Red
            write-host ": Make sure that the Exchange Trusted Subsystem has full control on the CNO for the DAG (use ADUC to check)."
            Write-Host "Press any key to continue ..."
            $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

            $mbxsrvs = (get-MailboxServer).name
            if ($dagmembers -eq "1") {
                foreach ($line in $mbxsrvs) {
                # Grants permission for Exchange Servers to the CNO and adds them to the DAG
                # Add-AdPermission -Identity "$dn" -User "$($Computer)$" -AccessRights GenericAll
                    Add-AdPermission -Identity "$dn" -User "$($line)$" -AccessRights GenericAll
                    Add-DatabaseAvailabilityGroupServer -Identity $dagname -MailboxServer $line
                }
            }
            if ($dagmembers -eq "2") {
                foreach ($line in $mbxsrvs) {
                 write-host " ";write-host "Do you want to add $line to your $dagname DAG? [y or n] " -NoNewline -ForegroundColor Green;4answer = read-host
                    if ($answer -eq "y") {
                        Add-AdPermission -Identity "$dn" -User "$($line)$" -AccessRights GenericAll
                        Add-DatabaseAvailabilityGroupServer -Identity $dagname -MailboxServer $line
                    }
                }
            }

Script Run Through
In my test lab I wanted to show the script in action. The first step is all the localized information you need to enter as well as the basic DAG creation:

DAGCreation-01
Then the DNS entry is created:

DAGCreation-02
After the DNS entry is validate, the script will then add one or more servers to your DAG:

DAGCreation-03
… and that’s it. You can validate results by looking that the Exchange Admin Center, DNS and ADUC:

DAG-Validation-ECP

DAG-Validation-ADUC

DAG-Validation-DNS

RemoveDAG Function

The RemoveDAG function is relatively simple. I’ve placed comments above each section as to what it does. I even have a ‘Are you sure?’ question just to make sure you want to go through a removal.

function DeleteDAG {
    write-host " ";write-host "Are you sure you want to remove your DAG?" -ForegroundColor Red;write-host " "
    Write-Host "Press any key to continue ..." -foregroundcolor white
    write-host " "
    $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

    # Remove all database copies
    $servers = (get-mailboxdatabase | Get-MailboxDatabaseCopyStatus |where {$_.status -eq "mounted"}).mailboxserver
    foreach ($line in $servers) {Get-MailboxDatabaseCopyStatus -server $line|remove-mailboxdatabasecopy -erroraction silentlycontinue}

    # Remove servers from the DAG
    $dagname = (Get-DatabaseAvailabilityGroup).name
    $names = ((Get-DatabaseAvailabilityGroup $dagname).servers).name
    foreach ($line in $names) {
        remove-DatabaseAvailabilityGroupServer -Identity $dagname -MailboxServer $line
    }

    # Remove computer object
    Get-ADComputer cu7dag | remove-adcomputer

    # Remove DNS Entry
    write-host " ";write-host "Specify a DNS Server Name or IP Address " -NoNewline -ForegroundColor Green;$server = read-host
    $dnsroot = (get-addomain).dnsroot
    remove-DnsServerResourceRecord -name $dagname -zonename $dnsroot -computername $server -rrtype a -erroraction silentlycontinue

    # Remove DAG itself
    Remove-DatabaseAvailabilityGroup $dagname
}

In action
RemoveDAG2
Notice each step will ask for you to confirm that you indeed want to remove the members from the DAG, to remove the DAG AD object or the Exchange DAG object as well.

Download the script
The script can be found on the TechNet Wiki Gallery.

Resources
I have a lot of good links for this script for you to read over for reference:

Add Computer Account to AD
Adding Windows Features
Add a DNS A record on a local DNS server
Remove a DNS A record on a local DNS server
CNO Pre-staging
Add-DatabaseAvailabilityGroupServer
Rights – written by a fellow Exchange MVP, I stumbled upon this while looking for how to add permissions for the computer objects to another computer object.
Exchange Trusted Subsystem – requires Full control because that is the account that is used by the Exchange Management Shell.
Rights issues – for Exchange 2010, but may apply to 2013 depending on your scenario.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s