NTS.Tools.MSADDS.psm1

function Install-NLASvcFixForDCs {
    <#
        .Description
        checks if dns is specified as dependy for service nlasvc and if its not the case it will add it.
 
        .Example
        Install-NLASvcFixForDCs
 
        .NOTES
         
    #>


    try {
        $RegKey = "HKLM:\SYSTEM\CurrentControlSet\Services\NlaSvc"
        $RegKeyValue = "DependOnService"
        $ServiceName = "DNS"

        Write-Verbose "adding service $($ServiceName) as dependency for service NlaSvc"
        $NLASvcDependencies = (Get-ItemProperty -Path $RegKey -Name $RegKeyValue).$RegKeyValue
        if ($NLASvcDependencies -notcontains $ServiceName) {
            $FixedNLASvcDependencies = $NLASvcDependencies + $ServiceName
            Set-ItemProperty -Path $RegKey -Name $RegKeyValue -Value $FixedNLASvcDependencies
            Write-Output "NlaSvc fix applied"
        }
        else {
            Write-Verbose "NlaSvc fix already applied"
        }
    }
    catch {
        throw $PSItem.Exception.Message
    }
}

function New-EASEOUStructure {
    <#
        .DESCRIPTION
        this will create the esae structure with OUs, User, Groups and Group Managed Service Accounts
 
        .PARAMETER LogFileName
        name of the log file
 
        .PARAMETER LogFileFolderPath
        path of the folder where to put the log file
 
        .PARAMETER Terminal
        writes to Terminal instead of log file
 
        .EXAMPLE
        New-EASEOUStructure
 
        .NOTES
        must be executed on a domain controller
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]
        $LogFileName,

        [Parameter(Mandatory = $false)]
        [string]
        $LogFileFolderPath,

        [Parameter(Mandatory = $false)]
        [bool]
        $Terminal
    )

    $ErrorActionPreference = 'Stop'
    $LogParam = Confirm-LogFileParameters -LogFileName $LogFileName -LogFileFolderPath $LogFileFolderPath -Terminal $Terminal

    #region functions
    function Add-ESAEADOU {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [string[]]
            $OUs,

            [Parameter(Mandatory = $true)]
            [string]
            $Path
        )
        
        try {
            $OUs | ForEach-Object {
                Write-Verbose "creating ou $($PSItem) at $($Path)"
                New-ADOrganizationalUnit -Name $PSItem -Path $Path
            }
        }
        catch {
            throw $PSItem.Exception.Message
        }
    }
    function New-ESAEADGroup {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [string]
            $Name,

            [Parameter(Mandatory = $true)]
            [string]
            $Path
        )
        
        try {
            Write-Verbose "creating group $($Name) at $($Path)"
            New-ADGroup -Name $Name -SamAccountName $Name -GroupCategory Security -GroupScope Universal -DisplayName $Name -Path $Path
        }
        catch {
            throw "$($Name) - $($PSItem.Exception.Message)"
        }
    }
    function New-ESAEADUser {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [string]
            $Name,

            [Parameter(Mandatory = $true)]
            [string]
            $Path,

            [Parameter(Mandatory = $true)]
            [string]
            $Domain,

            [Parameter(Mandatory = $true)]
            [securestring]
            $Password
        )
        
        try {
            Write-Verbose "creating user $($Name)@$($Domain) at $($Path)"
            New-ADUser -Name $Name -Path $Path -SamAccountName $Name -UserPrincipalName "$($Name)@$($Domain)" -GivenName $Name -DisplayName $Name -AccountPassword $Password -Enabled $true -PasswordNeverExpires $true
        }
        catch {
            throw "$($Name) - $($PSItem.Exception.Message)"
        }
    }
    function New-ESAEADServiceAccount {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [string]
            $Name,

            [Parameter(Mandatory = $true)]
            [string]
            $DNSHostName,

            [Parameter(Mandatory = $true)]
            [string]
            $PrincipalsAllowedToRetrieveManagedPwdGroup
        )
        
        try {
            Write-Verbose "creating gmsa $($DNSHostName)"
            New-ADServiceAccount -Name $Name -DNSHostName $DNSHostName -PrincipalsAllowedToRetrieveManagedPassword $PrincipalsAllowedToRetrieveManagedPwdGroup
        }
        catch {
            throw "$($Name) - $($PSItem.Exception.Message)"
        }
    }
    function Add-ESAEADGroupMember {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [string]
            $Group,

            [Parameter(Mandatory = $true)]
            [string[]]
            $Members
        )
        
        try {
            Write-Verbose "add $($Members) to group $($Group)"
            Add-ADGroupMember -Identity $Group -Members $Members
        }
        catch {
            throw "$($Name) - $($PSItem.Exception.Message)"
        }
    }
    #endregion

    try {
        if ((Get-CimInstance -ClassName Win32_OperatingSystem).ProductType -ne 2) {
            throw "this is not a domain controller, can only be used on domain controllers"
        }
    
        Import-Module "Activedirectory"
        $Domain = Get-ADDomain
    }
    catch {
        $ErrorMessage = "error - $($PSItem.Exception.Message)"
        Write-ToLogOrTerminal @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }

    Write-ToLogOrTerminal @LogParam -Severity Info -Message "apply esae structure on $($Domain.Forest)"
    
    #region ous
    try {
        Write-ToLogOrTerminal @LogParam -Severity Info -Message "creating ous"
        $TopLevelOU = 'ESAE'
        New-ADOrganizationalUnit -Name $TopLevelOU -Path $Domain.DistinguishedName

        # ESAE - create first level OUs
        $ESAEPath = "OU=$($TopLevelOU),$($Domain.DistinguishedName)"
        Add-ESAEADOU -OUs 'Groups', 'PAW', 'Tier 0', 'Tier 1', 'Tier 2' -Path $ESAEPath

        # ESAE\Tier0 - create second level OUs
        $Tier0Path = "OU=Tier 0,$($ESAEPath)"
        Add-ESAEADOU -OUs 'AD', 'PKI', 'SQL', 'ADFS', 'ADSync' -Path $Tier0Path

        # ESAE\Tier1 - create second level OUs
        $Tier1Path = "OU=Tier 1,$($ESAEPath)"
        Add-ESAEADOU -OUs 'Exchange', 'ConfigMgr', 'SQL', 'Fileserver', 'DHCP' -Path $Tier1Path

        # Create third level OUs
        # ESAE\Tier0\AD
        $Tier0ADPath = "OU=AD,$($Tier0Path)"
        Add-ESAEADOU -OUs 'Accounts', 'Groups' -Path $Tier0ADPath

        # Default OUs
        $DefaultSubOUs = 'Accounts', 'Devices', 'Groups'

        # Basis
        $PAWPath = "OU=PAW,$($ESAEPath)" # ESAE\PAW

        # Tier0
        $Tier0PKIPath = "OU=PKI,$($Tier0Path)" # ESAE\Tier0\PKI
        $Tier0SQLPath = "OU=SQL,$($Tier0Path)" # ESAE\Tier0\SQL
        $Tier0ADFSPath = "OU=ADFS,$($Tier0Path)" # ESAE\Tier0\ADFS
        $Tier0ADSyncPath = "OU=ADSync,$($Tier0Path)" # ESAE\Tier0\ADSync

        # Tier1
        $Tier1ConfigMgrPath = "OU=ConfigMgr,$($Tier1Path)" # ESAE\Tier1\ConfigMgr
        $Tier1SQLPath = "OU=SQL,$($Tier1Path)" # ESAE\Tier1\SQL
        $Tier1DHCPPath = "OU=DHCP,$($Tier1Path)" # ESAE\Tier1\DHCP
        $Tier1FileServerPath = "OU=Fileserver,$($Tier1Path)" # ESAE\Tier1\Fileserver
        $Tier1ExchangePath = "OU=Exchange,$($Tier1Path)" # ESAE\Tier1\Exchange

        # Tier2
        $Tier2Path = "OU=Tier 2,$($ESAEPath)" # ESAE\Tier2

        $OUsForWithDefault = @(
            $PAWPath
            $Tier0PKIPath
            $Tier0SQLPath
            $Tier0ADFSPath
            $Tier0ADSyncPath
            $Tier1ExchangePath
            $Tier1ConfigMgrPath
            $Tier1SQLPath
            $Tier1DHCPPath
            $Tier1FileServerPath
            $Tier2Path
        )
        foreach ($OU in $OUsForWithDefault) {
            Add-ESAEADOU -OUs $DefaultSubOUs -Path $OU
        }
    }
    catch {
        $ErrorMessage = "error creating ous - $($PSItem.Exception.Message)"
        Write-ToLogOrTerminal @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region groups
    try {
        Write-ToLogOrTerminal @LogParam -Severity Info -Message "creating groups"
        # PAW
        $GroupNames = 'T0-Allowed', 'T1-Allowed', 'T2-Allowed', 'T0-Denied', 'T1-Denied', 'T2-Denied'
        $GroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($ESAEPath)"
        }
        $PAWGroupNames = 'PAW-Devices', 'PAW-Maintenance', 'PAW-Users'
        $PAWGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($PAWPath)"
        }

        # T0
        $Tier0ADGroupNames = 'T0-CloudAdmins', 'T0-DomAdmins', 'T0-EntAdmins', 'T0-RODCAdmins', 'T0-SchAdmins'
        $Tier0ADGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier0ADPath)"
        }
        $Tier0PKIGroupNames = 'T0-PKIAdmins', 'T0-PKISCAgents'
        $Tier0PKIGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier0PKIPath)"
        }
        $Tier0SQLGroupNames = 'T0-SQLAdmins', 'T0-SQLServers'
        $Tier0SQLGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier0SQLPath)"
        }
        $Tier0ADFSGroupNames = 'T0-ADFSAdmins', 'T0-ADFSServers', 'T0-ADFSSQLServers'
        $Tier0ADFSGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier0ADFSPath)"
        }
        $Tier0ADSyncGroupNames = 'T0-ADSyncAdmins', 'T0-ADSyncServers', 'T0-ADSyncSQLServers'
        $Tier0ADSyncGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier0ADSyncPath)"
        }

        # T1
        $Tier1ExchangeGroupNames = 'T1-ExAdmins', 'T1-ExAllowed', 'T1-ExMaintenance', 'T1-ExMBXAdmins', 'T1-ExOrgAdmins'
        $Tier1ExchangeGroupNames | ForEach-Object { 
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier1ExchangePath)"
        }
        $Tier1CMGroupNames = 'T1-CMAdmins', 'T1-CMServers', 'T1-CMSQLServers'
        $Tier1CMGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier1ConfigMgrPath)"
        }
        $Tier1SQLGroupNames = 'T1-SQLAdmins', 'T1-SQLServers'
        $Tier1SQLGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier1SQLPath)"
        }
        $Tier1DHCPGroupNames = 'T1-DHCPAdmins', 'T1-DHCPServers'
        $Tier1DHCPGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier1DHCPPath)"
        }
        $Tier1FileServerGroupNames = 'T1-FileServerAdmins', 'T1-FileServerServers'
        $Tier1FileServerGroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier1FileServerPath)"
        }

        # T2
        $Tier2GroupNames = 'T2-HelpDesk'
        $Tier2GroupNames | ForEach-Object {
            New-ESAEADGroup -Name $PSItem -Path "OU=Groups,$($Tier2Path)"
        }
    }
    catch {
        $ErrorMessage = "error creating groups - $($PSItem.Exception.Message)"
        Write-ToLogOrTerminal @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region users
    try {
        Write-ToLogOrTerminal @LogParam -Severity Info -Message "creating users"
        $Password = ConvertTo-SecureString -String 'C0mplex' -AsPlainText -Force

        # PAW
        $PAWUserNames = 'PAWMan1'
        $PAWUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($PAWPath)" -Domain $Domain.Forest -Password $Password
        }
    
        # T0
        $Tier0ADUserNames = 'T0-DomAdmin1', 'T0-EntAdmin1'
        $Tier0ADUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier0ADPath)" -Domain $Domain.Forest -Password $Password
        }
        $Tier0PKIUserNames = 'T0-PKIAdmin1', 'T0-PKISCA1'
        $Tier0PKIUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier0PKIPath)" -Domain $Domain.Forest -Password $Password
        }
        $Tier0SQLUserNames = 'T0-SQLAdmin1', 'T0-SQLAdmin2'
        $Tier0SQLUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier0SQLPath)" -Domain $Domain.Forest -Password $Password
        }
        $Tier0ADFSUserNames = 'T0-ADFSAdmin1', 'T0-ADFSAdmin2'
        $Tier0ADFSUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier0ADFSPath)" -Domain $Domain.Forest -Password $Password
        }
        $Tier0ADSyncUserNames = 'T0-ADSyncAdmin1', 'T0-ADSyncAdmin2'
        $Tier0ADSyncUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier0ADSyncPath)" -Domain $Domain.Forest -Password $Password
        }
    
        # T1
        $Tier1ExchangeUserNames = 'T1-ExAdmin1', 'T1-ExAdmin2'
        $Tier1ExchangeUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier1ExchangePath)" -Domain $Domain.Forest -Password $Password
        }
        $Tier1CMUserNames = 'T1-CMAdmin1', 'T1-CMAdmin2', 'T1-CMSQLRPT'
        $Tier1CMUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier1ConfigMgrPath)" -Domain $Domain.Forest -Password $Password
        }
        $Tier1SQLUserNames = 'T1-SQLAdmin1', 'T1-SQLAdmin2'
        $Tier1SQLUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier1SQLPath)" -Domain $Domain.Forest -Password $Password
        }

        $Tier1DHCPUserNames = 'T1-DHCPAdmin1', 'T1-DHCPAdmin2'
        $Tier1DHCPUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier1DHCPPath)" -Domain $Domain.Forest -Password $Password
        }

        $Tier1FileServerUserNames = 'T1-FileServerAdmin1', 'T1-FileServerAdmin2'
        $Tier1FileServerUserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier1FileServerPath)" -Domain $Domain.Forest -Password $Password
        }
    
        # T2
        $Tier2UserNames = 'T2-HelpDesk1', 'T2-HelpDesk2'
        $Tier2UserNames | ForEach-Object {
            New-ESAEADUser -Name $PSItem -Path "OU=Accounts,$($Tier2Path)" -Domain $Domain.Forest -Password $Password
        }
    }
    catch {
        $ErrorMessage = "error creating users - $($PSItem.Exception.Message)"
        Write-ToLogOrTerminal @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region gmsa
    try {
        Write-ToLogOrTerminal @LogParam -Severity Info -Message "creating gmsa"
        Add-KdsRootKey -EffectiveTime (Get-Date).AddHours(-10) | Out-Null

        # T0
        New-ESAEADServiceAccount -Name "T0-SQLSvc" -DNSHostName "T0-SQLSvc.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-SQLServers"
        New-ESAEADServiceAccount -Name "T0-SQLAgt" -DNSHostName "T0-SQLAgt.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-SQLServers"
        # T0\ADFS
        New-ESAEADServiceAccount -Name "T0-ADFSSvc" -DNSHostName "T0-ADFSSvc.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-ADFSServers"
        New-ESAEADServiceAccount -Name "T0-ADFSSQLSvc" -DNSHostName "T0-ADFSSQLSvc.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-ADFSSQLServers"
        New-ESAEADServiceAccount -Name "T0-ADFSSQLAgt" -DNSHostName "T0-ADFSSQLAgt.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-ADFSSQLServers"
        # T0\ADSync
        New-ESAEADServiceAccount -Name "T0-ADSyncSvc" -DNSHostName "T0-ADSyncSvc.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-ADSyncServers"
        New-ESAEADServiceAccount -Name "T0-ADSyncSQLSvc" -DNSHostName "T0-ADSyncSQLSvc.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-ADSyncSQLServers"
        New-ESAEADServiceAccount -Name "T0-ADSyncSQLAgt" -DNSHostName "T0-ADSyncSQLAgt.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T0-ADSyncSQLServers"

        # T1
        New-ESAEADServiceAccount -Name "T1-SQLSvc" -DNSHostName "T1-SQLSvc.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T1-SQLServers"
        New-ESAEADServiceAccount -Name "T1-SQLAgt" -DNSHostName "T1-SQLAgt.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T1-SQLServers"
        # T1\ConfigMgr
        New-ESAEADServiceAccount -Name "T1-CMSQLSvc" -DNSHostName "T1-CMSQLSvc.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T1-CMSQLServers"
        New-ESAEADServiceAccount -Name "T1-CMSQLAgt" -DNSHostName "T1-CMSQLAgt.$($Domain.Forest)" -PrincipalsAllowedToRetrieveManagedPwdGroup "T1-CMSQLServers"
    }
    catch {
        $ErrorMessage = "error creating gmsa - $($PSItem.Exception.Message)"
        Write-ToLogOrTerminal @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region group membership
    try {
        Write-ToLogOrTerminal @LogParam -Severity Info -Message "creating group membership"
        # Tier Groups
        $Tier0AllowedGroups = 'T0-CloudAdmins', 'T0-DomAdmins', 'T0-EntAdmins', 'T0-RODCAdmins', 'T0-SchAdmins', 'T0-PKIAdmins', 'T0-PKISCAgents', 'T0-SQLAdmins', 'T0-ADFSAdmins', 'T0-ADSyncAdmins'
        $Tier1AllowedGroups = 'T1-CMAdmins', 'T1-ExAdmins', 'T1-ExAllowed', 'T1-ExMaintenance', 'T1-ExMBXAdmins', 'T1-ExOrgAdmins', 'T1-SQLAdmins'
        $Tier2AllowedGroups = 'T2-HelpDesk'
        Add-ESAEADGroupMember -Group 'T0-Allowed' -Members $Tier0AllowedGroups
        Add-ESAEADGroupMember -Group 'T0-Denied' -Members ($Tier1AllowedGroups + $Tier2AllowedGroups)
        Add-ESAEADGroupMember -Group 'T1-Allowed' -Members $Tier1AllowedGroups
        Add-ESAEADGroupMember -Group 'T1-Denied' -Members ($Tier0AllowedGroups + $Tier2AllowedGroups)
        Add-ESAEADGroupMember -Group 'T2-Allowed' -Members $Tier2AllowedGroups
        Add-ESAEADGroupMember -Group 'T2-Denied' -Members ($Tier0AllowedGroups + $Tier1AllowedGroups)

        # PAW
        Add-ESAEADGroupMember -Group 'PAW-Maintenance' -Members 'PAWMan1'

        # T0
        Add-ESAEADGroupMember -Group 'Domain Admins' -Members 'T0-DomAdmin1'
        Add-ESAEADGroupMember -Group 'Enterprise Admins' -Members 'T0-EntAdmin1'
        Add-ESAEADGroupMember -Group 'T0-PKIAdmins' -Members 'T0-PKIAdmin1'
        Add-ESAEADGroupMember -Group 'T0-PKISCAgents' -Members 'T0-PKISCA1'
        Add-ESAEADGroupMember -Group 'T0-SQLAdmins' -Members 'T0-SQLAdmin1', 'T0-SQLAdmin2'

        # T1
        Add-ESAEADGroupMember -Group 'T1-ExAdmins' -Members 'T1-ExAdmin1', 'T1-ExAdmin2'
        Add-ESAEADGroupMember -Group 'T1-CMAdmins' -Members 'T1-CMAdmin1', 'T1-CMAdmin2'
        Add-ESAEADGroupMember -Group 'T1-SQLAdmins' -Members 'T1-SQLAdmin1', 'T1-SQLAdmin2'
        Add-ESAEADGroupMember -Group 'T1-DHCPAdmins' -Members 'T1-DHCPAdmin1', 'T1-DHCPAdmin2'
        Add-ESAEADGroupMember -Group 'T1-FileServerAdmins' -Members 'T1-FileServerAdmin1', 'T1-FileServerAdmin2'

        # T2
        Add-ESAEADGroupMember -Group 'T2-HelpDesk' -Members 'T2-HelpDesk1', 'T2-HelpDesk2'
    }
    catch {
        $ErrorMessage = "error creating group memberships - $($PSItem.Exception.Message)"
        Write-ToLogOrTerminal @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion
}

function Repair-DFSRReplication {
    <#
        .Description
        this will forcefully repair dfsr replication on the domain, use with care
 
        .Example
        Repair-DFSRReplication
 
        .NOTES
        must be executed on a domain controller
         
    #>


    $Domain = (Get-ADDomain -Current LoggedOnUser).DistinguishedName
    $PDC = (Get-ADDomain).PDCEmulator
    $DCs = Get-ADObject -Filter { (objectclass -eq "computer") } -SearchBase "OU=Domain Controllers,$Domain" -Properties Name | Sort-Object Name
    
    $DCs | ForEach-Object {
        Invoke-Command -ComputerName $PSItem.Name -ScriptBlock {
            try {
                $Domain = (Get-ADDomain -Current LoggedOnUser).DistinguishedName
                $PDC = (Get-ADDomain).PDCEmulator
                $sysvolADObject = Get-ADObject -Filter { (objectclass -eq "msDFSR-Subscription") } `
                    -SearchBase "CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=$($env:COMPUTERNAME),OU=Domain Controllers,$Domain"`
                    -Properties "msDFSR-Options", "msDFSR-Enabled"
        
                Write-Output "Restarting NIC to correct Network Profile"
                $NetAdapter = Get-NetAdapter 
                $NetAdapter[0] | Restart-NetAdapter -Confirm:$false
    
                Write-Output "Installing DFSR Management Tools"
                Install-WindowsFeature -Name RSAT-DFS-Mgmt-Con | Out-Null
                if ($($PDC).Contains($env:COMPUTERNAME)) {
                    Write-Output "Setting msDFSR-Options to 1"
                    Set-ADObject -Identity $sysvolADObject.DistinguishedName -Replace @{"msDFSR-Options" = 1 }
                }
                Write-Output "Setting msDFSR-Enabled to false"
                Set-ADObject -Identity $sysvolADObject.DistinguishedName -Replace @{"msDFSR-Enabled" = $false }
            }
            catch {
                throw $PSItem.Exception.Message
            }
        }
    }
    
    Write-Output "Forcing AD Replication"
    repadmin /syncall /P /e
    Start-Sleep(10)

    Invoke-Command -ComputerName $PDC -ScriptBlock {
        try {
            $Domain = (Get-ADDomain -Current LoggedOnUser).DistinguishedName
            $sysvolADObject = Get-ADObject -Filter { (objectclass -eq "msDFSR-Subscription") } `
                -SearchBase "CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=$($env:COMPUTERNAME),OU=Domain Controllers,$Domain"`
                -Properties "msDFSR-Options", "msDFSR-Enabled"
            Write-Output "Restarting DFSR Service"
            Restart-Service DFSR 
            Start-Sleep(20)
            Write-Output "Setting msDFSR-Enabled to true"
            Set-ADObject -Identity $sysvolADObject.DistinguishedName -Replace @{"msDFSR-Enabled" = $true }
            Write-Output "Forcing AD Replication"
            repadmin /syncall /P /e
            Start-Sleep(10)
            Write-Output "Executing DFSRDIAG"
            dfsrdiag pollad
        }
        catch {
            $PSItem.Exception.Message
        }
    }
    
    $DCs | ForEach-Object {
        Invoke-Command -ComputerName $PSItem.Name -ScriptBlock {
            try {
                $Domain = (Get-ADDomain -Current LoggedOnUser).DistinguishedName
                $PDC = (Get-ADDomain).PDCEmulator
                $sysvolADObject = Get-ADObject -Filter { (objectclass -eq "msDFSR-Subscription") } `
                    -SearchBase "CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=$($env:COMPUTERNAME),OU=Domain Controllers,$Domain"`
                    -Properties "msDFSR-Options", "msDFSR-Enabled"
                if (!$($PDC).Contains($($env:COMPUTERNAME))) {
                    Write-Output "Restarting DFSR Service"
                    Restart-Service DFSR 
                    Start-Sleep(20)
                    Write-Output "Setting msDFSR-Enabled to true"
                    Set-ADObject -Identity $sysvolADObject.DistinguishedName -Replace @{"msDFSR-Enabled" = $true }
                    Write-Output "Executing DFSRDIAG"
                    dfsrdiag pollad  
                }
            }
            catch {
                throw $PSItem.Exception.Message
            }
        }
    }
}

function Compare-DFSRObject {
    [CmdletBinding()]

    $Domain = Get-ADDomain -Current LoggedOnUser
    $PDC = (Get-ADDomain).PDCEmulator
    $DCs = Get-ADObject -Filter { (objectclass -eq "computer") } -SearchBase "OU=Domain Controllers,$($Domain.DistinguishedName)" -Properties Name, DNSHostName | Where-Object -Property Name -NE "AzureADKerberos" | Sort-Object Name

    $Polices_CompareObject = @{}
    $Scripts_CompareObject = @{}

    # Get Files
    Write-Output "Getting data for comparison"
    $DCs | ForEach-Object {
        # C:\Windows\SYSVOL\sysvol\AZURE-HYBRID.DE\
        $PoliciesPath = "\\$($PSItem.DNSHostName)\C$\Windows\SYSVOL\domain\Policies"
        $ScriptsPath = "\\$($PSItem.DNSHostName)\C$\Windows\SYSVOL\domain\scripts"

        $Polices_CompareObject.add("$($PSItem.DNSHostName)", $(Get-ChildItem -Path $PoliciesPath).count)
        $Scripts_CompareObject.add("$($PSItem.DNSHostName)", $(Get-ChildItem -Path $ScriptsPath).count)
    }

    # Compare files count
    Write-Output "Comparing data"
    $Polices_CompareObject.Keys | ForEach-Object {
        if ($Polices_CompareObject."$($PDC)" -ne $Polices_CompareObject.$($PSItem)) {
            Write-Output "--------------------------------------------------------"
            Write-Warning "$($PSItem) is not in sync with $($PDC) at folder Policies"
            Write-Warning "$($PDC): $($Polices_CompareObject."$($PDC.Trim())") <---> $($PSItem): $($Polices_CompareObject.$($PSItem))"            
        }
        else {
            Write-Output "$($PSItem) is in sync with $($PDC) at folder Policies"
        }
    }
    $Scripts_CompareObject.Keys | ForEach-Object {
        if ($Scripts_CompareObject."$($PDC)" -ne $Scripts_CompareObject.$($PSItem)) {
            Write-Output "--------------------------------------------------------"
            Write-Warning "$($PSItem) is not in sync with $($PDC) at folder Scripts"
            Write-Warning "$($PDC): $($Scripts_CompareObject."$($PDC.Trim())") <---> $($PSItem): $($Scripts_CompareObject.$($PSItem))"            
        }
        else {
            Write-Output "$($PSItem) is in sync with $($PDC) at folder Scripts"
        }
    }
}