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
 
        .Example
        New-EASEOUStructure
 
        .NOTES
        must be executed on a domain controller
    #>


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

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

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

    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)"
        }
    }

    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-ToLogOrConsole @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }

    Write-ToLogOrConsole @LogParam -Severity Info -Message "apply esae structure on $($Domain.Forest)"
    
    #region ous
    try {
        Write-ToLogOrConsole @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-ToLogOrConsole @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region groups
    try {
        Write-ToLogOrConsole @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-ToLogOrConsole @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region users
    try {
        Write-ToLogOrConsole @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-ToLogOrConsole @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region gmsa
    try {
        Write-ToLogOrConsole @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-ToLogOrConsole @LogParam -Severity Error -Message $ErrorMessage
        throw $ErrorMessage
    }
    #endregion

    #region group membership
    try {
        Write-ToLogOrConsole @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-ToLogOrConsole @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"
        }
    }
}