terraform-provider-ad icon indicating copy to clipboard operation
terraform-provider-ad copied to clipboard

Do not complete apply until object is replicated

Open redeux opened this issue 4 years ago • 4 comments

Description

When using Active Directory replication, a new object created a one location needs to be replicated to one or more other locations. In this scenario, when the object is created, it may also be needed at the replication targets for the workflow to continue successfully.

Potential Terraform Configuration

References

https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/replication/active-directory-replication-concepts

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

redeux avatar Dec 16 '20 19:12 redeux

Question :

Should the replication be enforced or wait until normal replication is done ?

jpatigny avatar Dec 16 '20 23:12 jpatigny

Got a piece of code to force replication (and ensure it's replicated on all DC's). I'm still not sure if it's the best approach to take.

Here is the code, feel free to comment :

function Sync-DomainController {
    [CmdletBinding()]
    param(
        [string] $Domain = $Env:USERDNSDOMAIN
    )
    $DistinguishedName = (Get-ADDomain -Server $Domain).DistinguishedName
    (Get-ADDomainController -Filter * -Server $Domain).Name | ForEach-Object {
        Write-Verbose -Message "Sync-DomainController - Forcing synchronization $_"
        repadmin /syncall $_ $DistinguishedName /e /A | Out-Null
    }
}

function Get-WinADForestReplicationPartnerMetaData {
    [CmdletBinding()]
    param(
        [switch] $Extended
    )
    $Replication = Get-ADReplicationPartnerMetadata -Target * -Partition * -ErrorAction SilentlyContinue -ErrorVariable ProcessErrors
    if ($ProcessErrors) {
        foreach ($_ in $ProcessErrors) {
            Write-Warning -Message "Get-WinADForestReplicationPartnerMetaData - Error on server $($_.Exception.ServerName): $($_.Exception.Message)"
        }
    }
    foreach ($_ in $Replication) {
        $ServerPartner = (Resolve-DnsName -Name $_.PartnerAddress -Verbose:$false -ErrorAction SilentlyContinue)
        $ServerInitiating = (Resolve-DnsName -Name $_.Server -Verbose:$false -ErrorAction SilentlyContinue)
        $ReplicationObject = [ordered] @{
            Server                         = $_.Server
            ServerIPV4                     = $ServerInitiating.IP4Address
            ServerPartner                  = $ServerPartner.NameHost
            ServerPartnerIPV4              = $ServerPartner.IP4Address
            LastReplicationAttempt         = $_.LastReplicationAttempt
            LastReplicationResult          = $_.LastReplicationResult
            LastReplicationSuccess         = $_.LastReplicationSuccess
            ConsecutiveReplicationFailures = $_.ConsecutiveReplicationFailures
            LastChangeUsn                  = $_.LastChangeUsn
            PartnerType                    = $_.PartnerType
            Partition                      = $_.Partition
            TwoWaySync                     = $_.TwoWaySync
            ScheduledSync                  = $_.ScheduledSync
            SyncOnStartup                  = $_.SyncOnStartup
            CompressChanges                = $_.CompressChanges
            DisableScheduledSync           = $_.DisableScheduledSync
            IgnoreChangeNotifications      = $_.IgnoreChangeNotifications
            IntersiteTransport             = $_.IntersiteTransport
            IntersiteTransportGuid         = $_.IntersiteTransportGuid
            IntersiteTransportType         = $_.IntersiteTransportType
            UsnFilter                      = $_.UsnFilter
            Writable                       = $_.Writable
        }
        if ($Extended) {
            $ReplicationObject.Partner = $_.Partner
            $ReplicationObject.PartnerAddress = $_.PartnerAddress
            $ReplicationObject.PartnerGuid = $_.PartnerGuid
            $ReplicationObject.PartnerInvocationId = $_.PartnerInvocationId
            $ReplicationObject.PartitionGuid = $_.PartitionGuid
        }
        [PSCustomObject] $ReplicationObject
    }
}

function Start-ADSync
{
    $now = Get-Date
    Write-Output "Starting sync at $now"
    $sync = $false

    do
    {
       # Force sync
       Sync-DomainController

       # Ensure replication is applied on all AD
       $results = Get-WinADForestReplicationPartnerMetaData
       
       Write-Output "----"
       foreach ($result in $results) {
        if ($result.LastReplicationSuccess -gt $now) {
            Write-Output "[Sync OK] Started: $now < ended successfully: $($result.LastReplicationSuccess)"
            $sync = $true
        }
        else {
            Write-Output "[Sync KO] Started: $now > ended successfully: $($result.LastReplicationSuccess)"
            $sync = $false
        }
       }
       Write-Output "----"
    }
    until ($sync)
    return "Sync finished on all DC's"
}

Start-ADSync

Source for the functions : evotec.xyz

jpatigny avatar Dec 30 '20 10:12 jpatigny

About this request,

Got a few points that i'd like to clarify :

  • Do we consider the replication as mandatory or do we give the choice to the user to enable it (via a setting in the provider for example) ?
  • Do we trigger a manual replication on all DC''s or do we check/wait for normal replication process to be finished ?
  • If we force replication, do we synchronize all objects or only objects that were created/modified ?
  • Is replication useful when object are deleted ?

My two cents on that :

I would trigger the replication manually from the domain controller the server is connected to ($env:LOGONSERVER) all other domain controllers. I would trigger a sync after each object create and update using cmdlet Sync-ADObject (Link) I would force a sync of all object after a deletion of object only.

Comments are welcome. I don't know if there is a perfect way to implement this...

jpatigny avatar Jan 31 '21 23:01 jpatigny

Another option would be to select one of the domain controllers and only work with that one server and let natural replication happen. Something like (Get-ADDomainController | Select-Object -First 1).HostName would work. You could even tie it to a switch like persistant_dc. I would love to see this implemented, where I work has a rather large replicated AD environment but with the way the module is now I can't use it. Constantly get the errors stating the object was present but is now absent

ncecere avatar Aug 13 '21 20:08 ncecere