dsccommunity / DnsServerDsc

This module contains DSC resources for the management and configuration of Windows Server DNS Server.
MIT License
65 stars 54 forks source link

DnsServerADZone fails when attempting to make changes on boot #51

Open achern opened 7 years ago

achern commented 7 years ago

My DSC configuration brings up a combo DNS server and Domain Controller. After the xADDomain resource installs the forest/domain, the server reboots. Then, after waiting for the domain to come up, I use xDnsServerADZone to make sure DNS is integrated with Active Directory (it already is, but I would like to enforce the configuration):

    xWaitForADDomain DomainWait {
        DependsOn = '[xADDomain]Domain'
        DomainName = $DomainName
    }

    xDnsServerADZone ADIntegratedDnsEnabled {
        DependsOn = '[xWaitForADDomain]DomainWait'
        Name = $DomainName
        Ensure = 'Present'
        ReplicationScope = 'Domain'
        DynamicUpdate = 'Secure'
    }

At this point, xDnsServerADZone fails with the message:

ErrorMessage: Failed to reset the directory partition for zone ad.test.com on server DC1.
Message ID: WIN32 9901,Set-DnsServerPrimaryZone
ErrorCategory: 13
ErrorCode: 13
ErrorType: MI

After some experimenting, it seems that on first boot, the DNS zone's ReplicationScope has a value of 'Legacy' for a minute or two before changing to 'Domain' (I wasn't able to find any documentation explaining this behavior). Attempting to call Set-DnsServerPrimaryZone to change it during this time results in the above error. On the next DSC pass, the configuration is able to apply successfully. Alternatively, if I add a Script resource to sleep for two minutes before xDnsServerADZone, it is also successful.

Thus, it seems like xDnsServerADZone needs to wait until the 'Legacy' value goes away before attempting to modify ReplicationScope.

The server is running a Windows Server 2012 R2 Core image with minimal tweaks (all updates through about July, WMF 5.1 installed, DSC Resource Kit installed) on Windows 10 Hyper-V. I am using xActiveDirectory 2.16.0.0 and xDnsServer 1.7.0.0.

Host:

$PSVersionTable
Name                           Value
----                           -----
PSVersion                      5.1.14393.1358
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14393.1358
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Server VM:

$PSVersionTable
Name                           Value
----                           -----
PSVersion                      5.1.14409.1005
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14409.1005
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
johlju commented 6 years ago

The easiest solution would be if the configuration want to set ReplicationScope = 'Domain' and if ReplicationScope -eq 'Legacy' then the Test-TargetResource could possibly retry for a while to see if the value changes, if it hasn't change within $RetryTimeout the resource fails.

LoSaMe commented 3 years ago

I'm running in the same problem/scenario like achern there. The problem is that in my DC configuration are other recourses like DfsDsc that needs a working DNS to be deployed. So the DFS is failing because it is dependent on the DNS after the reboot.

After some minutes the zones coming up but DFS already failed. Are there maybe some more suggestions to this topic?

johlju commented 3 years ago

It sounds lika se need to have a WaitForADZone that waits for the zone to change state (according to @achern description) in a time out period (if it never changes it must timeout and fail).

This could be a composite resource that uses a script resource. But could preferably be a real resource.

@LoSaMe could you make the needed logic to wait for the zone to come up in a script resource and paste it here? Or maybe even contribute a composite or resource? But if we have the logic it I should be quicker for someone else to pick it up.

bjoka042 commented 3 years ago

I had the same problem and wrote a script to wait for 'Legacy' to change.

...

$Node = @{
    Domain  = @{
        DomainName = 'mydomain.local'
    }
    ADZones = @(
        @{ 
            Name             = 'mydomain.local';
            DynamicUpdate    = 'Secure';
            ReplicationScope = 'Forest';
            Ensure           = 'Present'
        }
    )        
}

...

WaitForADDomain 'DomainWait' {
    DomainName   = $Node.Domain.DomainName
    Credential   = $DomainAdminCredential
    WaitTimeout  = 300
    RestartCount = 5
    DependsOn    = @('[ADDomain]DC')
}

$Count = 0
foreach ($ADZone in $Node.Domain.ADZones) {
    $Count++

    Script "WaitForADZone$Count" {
        GetScript  = { 
            Return $@ {} 
        }
        SetScript  = { }
        TestScript = { 
            $zoneName = $using:ADZone.Name
            $sleepSeconds = 60
            $attempts = 10
            $attempt = 1
            $succeded = $true

            $zone = Get-DnsServerZone -Name $zoneName -ErrorAction SilentlyContinue
            if ($zone) {
                Write-Verbose "DnsServerZone '$zoneName' exists and has ReplicationScope '$($zone.ReplicationScope)'."

                while ($succeded -and $zone.ReplicationScope -eq 'Legacy') {
                    Write-Verbose "DnsServerZone '$zoneName' has ReplicationScope 'Legacy', waiting for AD to change it."
                    Write-Verbose "Sleep $sleepSeconds seconds ($attempt/$attempts) to let domain info load."

                    Start-Sleep -Seconds $sleepSeconds
                    $attempt += 1

                    $zone = Get-DnsServerZone -Name $zoneName -ErrorAction SilentlyContinue
                    if (-not($zone)) {
                        Write-Verbose "Failed to get ADZone '$zoneName'."
                        $succeded = $false
                    }
                    if ($attempt -gt $attempts) {
                        Write-Verbose "Waiting for DnsServerZone '$zoneName' to change ReplicationScope from 'Legacy' failed with max attempts."
                        $succeded = $false
                    }
                }
            }
            Return $succeded 
        }
        DependsOn  = @('[WaitForADDomain]DomainWait')
    }

    DnsServerADZone "ADZone_$Count" {
        Name             = $ADZone.Name
        DynamicUpdate    = $ADZone.DynamicUpdate
        ReplicationScope = $ADZone.ReplicationScope
        Ensure           = $ADZone.Ensure
        DependsOn        = @('[WaitForADDomain]DomainWait', "[Script]WaitForADZone$Count")
    }
}