Powershell Script: Troubleshooting Locked Accounts

Hi All,

 

Here's a quick PowerShell script to find locked accounts.

 

## Define the username that’s locked out
$Username = ‘abertram’
## Find the domain controller PDCe role
$Pdce = (Get-AdDomain).PDCEmulator
## Build the parameters to pass to Get-WinEvent
$GweParams = @{
     ‘Computername’ = $Pdce
     ‘LogName’ = ‘Security’
     ‘FilterXPath’ = "*[System[EventID=4740] and EventData[Data[@Name='TargetUserName']='$Username']]"
}
## Query the security event log
$Events = Get-WinEvent @GweParams

 

 

Enjoy!!!

Powershell Script: Monitor Expired/Expiring Certificates

Hi All,

 

Happy new year. Its been sometime since my last update/post. I've been extremely busy with clients in and put of Australia, and as a result of this had no time for any blog posts.

 

Now I got plenty of time and want to enjoy what I do best and that is share my powershell scripts.

 

Below is a script that monitors your systems for expired/expiring certificates. Its very easy to use and implement.

 

<#

FileName: Cert-Mon.ps1

Description: Monitor Certificates and get expiration day

Written by Michael Aksoy


#>


#region "Functions"

#========================================================================================
# Log function
#========================================================================================
function Write-Log($log)
{
    [string] $MsgLog = ""
    $CurrentDate2 = Get-Date
    $MsgLog = "$CurrentDate2 --> $log"
    Add-Content -Path $LogFile -Value $MsgLog
}
#========================================================================================

function Write-Info($log)
{
    [string] $MsgLog = ""
    $MsgLog = $log
    Add-Content -Path $LogFile -Value $MsgLog
}
#========================================================================================

 

#endregion

#region "Global Variables"
CLS
$TimeVal = Get-Date -UFormat "%Y-%m-%d-%H-%M"
$DateFormat = Get-Date -Format "yyyyMMdd_HHmmss"
$CurrentDate = Get-Date
$CurrentDay = $CurrentDate.Day.ToString()
$CurrentMonth = (Get-Date -UFormat "%b").ToString()
$CurrentDayOfWeek = $CurrentDate.DayOfWeek.ToString()
$CurrentYear = $CurrentDate.Year.ToString()
$LogDir = "C:\Dev\Logs\Certs\"
$LogFileName = $CurrentDayOfWeek + "_Mon-CertsLog.txt"
$LogFile = $LogDir + $LogFileName

$DaysToExpiration = 90 #change this once it's working
 
$expirationDate = (Get-Date).AddDays($DaysToExpiration) # Expiration Date of Certs


#endregion

try{

    #region "Create LogFile"
        IF (!(Test-Path $LogDir)) {new-item -type Directory -path $LogDir} 


        if(Test-Path $LogFile)
        {
            $FileLastModifiedDate = Get-Item $LogFile | Select LastWriteTime
            $FileDate = $FileLastModifiedDate.LastWriteTime.ToShortDateString()
            $NewFileDate = $CurrentDate.ToShortDateString()


            if($FileDate -ne $NewFileDate) #Delete Old log File to start a fresh one
            {
                Remove-Item $LogFile
            }
        }


   
        if(!(Test-Path $LogFile))
        {
            Write-Output "*********************************************** $($CurrentDate) Logging Started ************************************************************" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile
        }else{


            Write-Output "*********************************************** $($CurrentDate) Append Logging ************************************************************" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile
        }

    #endregion

    #Now lets get those expiring Certs

    $ExpiredCerts = Get-ChildItem -Path Cert: -Recurse | where { $_.notafter -le $expirationDate -AND $_.notafter -gt (get-date)} | select FriendlyName, Thumbprint, Subject, Location, NotAfter, Issuer
    $AllCerts = @() # Collect all Expired Certs
   
    if(![string]::IsNullOrEmpty($ExpiredCerts))
    {
        Write-Log ("The following Certificates will Expire or have expired in $($DaysToExpiration) day(s)")
        Write-Host ("The following Certificates will Expire or have expired in $($DaysToExpiration) day(s)") -ForegroundColor Yellow

        ForEach($CertEx in $ExpiredCerts)
        {
            if([string]::IsNullOrEmpty($CertEx.FriendlyName))
            {
                Write-Host "Certificate with Thumbprint $($CertEx.Thumbprint) is due for renewal. It expires on $($CertEx.NotAfter)" -ForegroundColor Yellow
            }
            else{
                Write-Host "Certificate $($CertEx.FriendlyName) is due for renewal. It expires on $($CertEx.NotAfter)" -ForegroundColor Yellow

            }

            $AllCerts += $CertEx

            Write-Log ("********* Expiring Cerificate **********")
            Write-Log ("`n")
            Write-Log ("FriendlyName: $($CertEx.FriendlyName)")
            Write-Log ("Location: $($CertEx.Location)")
            Write-Log ("Subject: $($CertEx.Subject)")
            Write-Log ("Thumbprint: $($CertEx.Thumbprint)")
            Write-Log ("Expires On: $($CertEx.NotAfter)")
            Write-Log ("Cert Issuer: $($CertEx.Issuer)")
            Write-Log ("`n")
            Write-Log ("****************************************")

        }

    }

    If($AllCerts.Count -gt 0)
    {
        Write-Log "All Expired or Expiring Certs"
        Write-Info "`n"
        Write-Info "$($AllCerts | FT -AutoSize | Out-String)"
    }


}
catch [Exception]
{
      $EndDate = Get-Date

      Write-Log ("Error executing script: $($_.Exception.Message)")
      Write-Log ("Exiting Script")
      Write-Output "*********************************************** $($EndDate) Logging Finished ************************************************************" | Add-Content $LogFile
      Write-Output "`n" | Add-Content $LogFile
      exit(1)

}
$EndDate = Get-Date

Write-Output "*********************************************** $($EndDate) Logging Finished ************************************************************" | Add-Content $LogFile
Write-Output "`n" | Add-Content $LogFile

 

 

Enjoy

Powershell: Wrapper for RepAdmin

Hi Guys,

Sorry I haven't being blogging for a while, as I've been extremely busy at client sites troubleshooting/building/designing public and private clods as well as Active Directory running on virtual machines.

One of the most important aspect of being and Active Directory Administrator is being able to troubleshoot and identify problems. RepAdmin is such a cool that it has everything. Unfortunately it's sometimes hard to remember all the necessary commands, unless you visit Microsoft. to simplify this I've created an powershell wrapper specifically for repadmin. This wrapper has all the common functions of repadmin as well as some of the advanced functions.

#region "Help and Information"
<#

.SYNOPSIS
  Active Directory Replication

.DESCRIPTION
  The Script will act as a wrapper for RepAdmin and will allow fucntions to initiate repliaction and collect information

.EXAMPLE
    Check Replication Topology

    Replicate-AD.ps1 -CheckReplicationTopology $true

.EXAMPLE
    Replicate Topology

    Replicate-AD.ps1 -ReplicateTopology $true

.EXAMPLE
    Show Domain Controller Connections

    Replicate-AD.ps1 -GetServerConnections $true

.EXAMPLE
    Show Replication Signature of A Domain Controller

    Replicate-AD.ps1 -GetSignatures $true

.EXAMPLE
    Show Context Handles for the Replication Process

    Replicate-AD.ps1 -GetHandles $true

.EXAMPLE
    Display the Highest Update Sequence Number (USN) on a Domain Controller

    Replicate-AD.ps1 -GetUsn $true

.EXAMPLE
    Summarise replication changes pending

    Replicate-AD.ps1 -GetUnReplicatedChanges $true

.EXAMPLE
    Show Replication Status; Displays the replication partners of a particular Domain Controller

    Replicate-AD.ps1 -ShowReplicationStatus $true

.EXAMPLE
    Summarise Replication Status

    Replicate-AD.ps1 -SummariseReplicationStatus $true

.EXAMPLE
    Show Active Directory Backup

    Replicate-AD.ps1 -ShowLastBackupStatus $true

.EXAMPLE
    Show Replication BackLog (Replication Queue)

    Replicate-AD.ps1 -CheckReplicationBackLog $true

.EXAMPLE
    Get All Bridgehead Servers

    Replicate-AD.ps1 -GetBridgeHeadServersInfo $true

.EXAMPLE
    Display all outcalls, which have not been answered

    Replicate-AD.ps1 -GetAllOutCalls $true

.EXAMPLE
    Generate ISTG Report

    Replicate-AD.ps1 -GetISTGReport $true

.EXAMPLE
    Show all Domain Trusts

    Replicate-AD.ps1 -ShowAllTrusts $true

.EXAMPLE
    Show Active Directory Latency

    Replicate-AD.ps1 -ShowRepLatency $true

.EXAMPLE
    Check/Monitor NTP

    Replicate-AD.ps1 -MonitorNTP $true

.EXAMPLE
    Check the RID Manager

    Replicate-AD.ps1 -CheckRidPool $true

.EXAMPLE
    Draw Topology

    Replicate-AD.ps1 -DrawTopology $true

.EXAMPLE
    Check DFS-R Backlogs

    Replicate-AD.ps1 -CheckDfsr $true

.EXAMPLE
    Check UPN Name (Only on Windows Server 2008 R2 and above)

    Replicate-AD.ps1 -CheckSPNSandUPNS $true -UPNName "user@contoso.com"

.EXAMPLE
    Check SPN Name (Only on Windows Server 2008 R2 and above)

    Replicate-AD.ps1 -CheckSPNSandUPNS $true -SPNName "http/www.contoso.com"

.EXAMPLE
    Find Duplicate UPNs (Only on Windows Server 2008 R2 and above)

    Replicate-AD.ps1 -CheckSPNSandUPNS $true -FindDuplicateUPNS $true

.EXAMPLE
    Find Duplicate SPNs (Only on Windows Server 2008 R2 and above)

    Replicate-AD.ps1 -CheckSPNSandUPNS $true -FindDuplicateSPNS $true

.EXAMPLE
    Generate Site Report

    Replicate-AD.ps1 -SiteReport $true

.EXAMPLE
    Get Current FSMO Role Owners

    Replicate-AD.ps1 -FsmoRoles $true

.EXAMPLE
    Create Token Size Report with Default Settings

    Replicate-AD.ps1 -KerberosTokenSizeReport $true

.EXAMPLE
    Create Token Size Report, Set the number of users with large tokens

    Replicate-AD.ps1 -KerberosTokenSizeReport $true -TopUsers 500

.EXAMPLE
    Create Token Size Report, Set the token threshold size in bytes that you want to start the capture

    Replicate-AD.ps1 -KerberosTokenSizeReport $true -TokensSizeThreshold 10000

.EXAMPLE
    Create Token Size Report, Display OutPut on Screen (Default is True)

    Replicate-AD.ps1 -KerberosTokenSizeReport $true -DisplayOutputOnScreen $false

.EXAMPLE
    Create Token Size Report, Use "GetAuthorizationGroups"

    Replicate-AD.ps1 -KerberosTokenSizeReport $true -DisplayOutputOnScreen $false


.NOTES
   Version 1.0: initial Script, Topology Replication
   Version 1.1: Display Server connections, Get Signatures, Get Contetx Handles
   Version 1.2: Show Updated Sequence Number (USN), Show Un-replicated Changes
   Version 1.3: Display Summary of Pending replications, Get Failed Replications
   Version 1.4: Get Replication Status of Each Domain Controller, Summarise the Replication Status
   Version 1.5: Fixed ShowRepl and ReplSum Outputs. Made it more readable and understandable
   Version 1.6: Show AD Queues, Check AD BackLog (Replication Queue)
   Version 1.7: Get All Bridge Head Servers
   Version 1.8: Display all outcalls, which have not been answered
   Version 1.9: Generate an ISTG Report
   Version 2.0: Get All Domain Trusts
   Version 2.1: Show Replication Latency
   Version 2.2: Monitor Active Directory NTP Source
   Version 2.3: Corrected Formating for Active Directory Backups, Minor bug fixes
   Version 2.4: Get Rid pool Information
   Version 2.5: Draw Active Directory Topology
   Version 2.6: Check DFS-R Backlog
   Version 2.7: Check SPNs, UPNs, Duplicate SPNs, and Duplicate UPNs
   Version 2.8: Get Active Directory Site Information and Fsmo Roles
   Version 2.9: Create a Sitelink and Site Cost report
   Version 3.0: Create Kerberos Token Size Report
   Written by Michael Aksoy
   Supported OS: Windows Server 2003/2003 R2/2008/2008 R2/2012/2012 R2
   Powershell Versions: Powershell 2 and above
   AnyCloud Pty Ltd
   Date: 16.03.2014
   www.anycloud.com.au
   blogs.anycloud.com.au

#>

#endregion

#region "Script Parameters"
param(
    [Parameter(Mandatory=$false)]
    [bool]$ReplicateTopology=$false,
    [Parameter(Mandatory=$false)]
    [bool]$CheckReplicationTopology=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetServerConnections=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetSignatures=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetHandles=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetUSN=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetUnReplicatedChanges=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetFailedReplications=$false,
    [Parameter(Mandatory=$false)]
    [bool]$ShowReplicationStatus=$false,
    [Parameter(Mandatory=$false)]
    [bool]$SummariseReplicationStatus=$false,
    [Parameter(Mandatory=$false)]
    [bool]$ShowLastBackupStatus=$false,
    [Parameter(Mandatory=$false)]
    [bool]$CheckReplicationBackLog=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetBridgeHeadServersInfo=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetAllOutCalls=$false,
    [Parameter(Mandatory=$false)]
    [bool]$GetISTGReport=$false,
    [Parameter(Mandatory=$false)]
    [bool]$ShowAllTrusts=$false,
    [Parameter(Mandatory=$false)]
    [bool]$ShowRepLatency=$false,
    [Parameter(Mandatory=$false)]
    [bool]$MonitorNTP=$false,
    [Parameter(Mandatory=$false)]
    [bool]$CheckRidPool=$false,
    [Parameter(Mandatory=$false)]
    [bool]$DrawTopology=$false,
    [Parameter(Mandatory=$false)]
    [bool]$CheckDfsr=$false,
    [Parameter(Mandatory=$false)]
    [bool]$CheckSPNSandUPNS=$false,
    [Parameter(Mandatory=$false)]
    [bool]$FindDuplicateSPNs=$false,
    [Parameter(Mandatory=$false)]
    [bool]$FindDuplicateUPNs=$false,
    [Parameter(Mandatory=$false)]
    [string]$SPNName= "",
    [Parameter(Mandatory=$false)]
    [string]$UPNName= "",
    [Parameter(Mandatory=$false)]
    [bool]$SiteReport=$false,
    [Parameter(Mandatory=$false)]
    [bool]$FsmoRoles=$false,
    [Parameter(Mandatory=$false)]
    [bool]$KerberosTokenSizeReport=$false,
    [Parameter(Mandatory=$false)]
    [bool]$DisplayOutputOnScreen=$true,
    [Parameter(Mandatory=$false)]
    [int]$TopUsers= 200,
    [Parameter(Mandatory=$false)]
    [int]$TokensSizeThreshold= 6000,
    [Parameter(Mandatory=$false)]
    [bool]$UserTokenGroups=$True,
    [Parameter(Mandatory=$false)]
    [bool]$UseGetAuthorizationGroups=$false
   
   
)


#endregion

#region "Functions"

#region "Functions for Token Size"

Function Get-UserPrincipal($cName, $cContainer, $userName)
{
  $dsam = "System.DirectoryServices.AccountManagement"
  $rtn = [reflection.assembly]::LoadWithPartialName($dsam)
  $cType = "domain" #context type
  $iType = "SamAccountName"
  $dsamUserPrincipal = "$dsam.userPrincipal" -as [type]
  $principalContext = new-object "$dsam.PrincipalContext"($cType,$cName,$cContainer)
  $dsamUserPrincipal::FindByIdentity($principalContext,$iType,$userName)
} # end Get-UserPrincipal
 
Function Test-DotNetFrameWork35
{
 Test-path -path 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5'
} #end Test-DotNetFrameWork35

#endregion

#region "DFS-R Functions"

#Reference -->http://gallery.technet.microsoft.com/scriptcenter/dac62790-219d-4325-a57b-e79c2aa6b58e

Function PingCheck
{
    Param
    (
        [string]$Computer = "localhost",
        [int]$timeout = 120
    )
    Write-Debug $computer
    Write-Debug $timeout
    $Ping = New-Object System.Net.NetworkInformation.Ping
    trap 
    {
        Write-Host "`nThe computer $computer could not be resolved" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> The computer $computer could not be resolved" | Add-Content $LogFile
        #Write-Debug "The computer $computer could not be resolved."       
        continue
    } 
   
    #Write-Debug "Checking server: $computer"
    Write-Host "`nChecking server: $computer" -ForegroundColor Green
    Write-Output "`n$CurrentDate --> Checking server: $computer" | Add-Content $LogFile       
    $reply = $Ping.Send($computer,$timeout)
    Write-Debug $reply
    If ($reply.status -eq "Success") 
    {
       
        Write-Host "`nPinging Server $computer passed." -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Pinging Server $computer passed." | Add-Content $LogFile
        Write-Output $True 
    } else {
        
        Write-Host "`nPinging Server $computer failed." -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Pinging Server $computer failed." | Add-Content $LogFile
        Write-Output $False
    }  
   
}
 
Function Check-WMINamespace ($computer, $namespace)
{
    $Namespaces = $Null
    $Namespaces = Get-WmiObject -class __Namespace -namespace root -computername $computer | Where {$_.name -eq $namespace}
    If ($Namespaces.Name -eq $Namespace)
    {
       
        Write-Host "`nNamespace connection to Server $computer passed." -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Namespace connection to Server $computer passed." | Add-Content $LogFile
        Write-Output $True  
    } else {
       
        Write-Host "`nNamespace connection to Server $computer failed." -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Namespace connection to Server $computer failed." | Add-Content $LogFile
        Write-Output $False 
    }
}
 
Function Get-DFSRGroup ($computer, $RGName)
{
    ## Query DFSR groups from the MicrosftDFS WMI namespace.
    If ([string]::IsNullOrEmpty($RGName))
    {
        $WMIQuery = "SELECT * FROM DfsrReplicationGroupConfig"
    } else {
        $WMIQuery = "SELECT * FROM DfsrReplicationGroupConfig WHERE ReplicationGroupName='" + $RGName + "'"
    }
    $WMIObject = Get-WmiObject -computername $computer -Namespace "root\MicrosoftDFS" -Query $WMIQuery
    Write-Output $WMIObject
    Write-Host "`nQuerying WMI DFSR Namespace $WMIObject" -ForegroundColor Green
    Write-Output "`n$CurrentDate --> Querying WMI DFSR Namespace $WMIObject" | Add-Content $LogFile
}
 
Function Get-DFSRConnections ($computer)
{
    ## Query DFSR connections from the MicrosftDFS WMI namespace.
    $WMIQuery = "SELECT * FROM DfsrConnectionConfig"
    $WMIObject = Get-WmiObject -computername $computer -Namespace "root\MicrosoftDFS" -Query $WMIQuery
    Write-Output $WMIObject
    Write-Host "`nQuerying DFSR connections $WMIObject" -ForegroundColor Green
    Write-Output "`n$CurrentDate --> Querying DFSR connections $WMIObject" | Add-Content $LogFile
}
 
 
Function Get-DFSRFolder ($computer, $RFname)
{
    ## Query DFSR folders from the MicrosftDFS WMI namespace.
    If ([string]::IsNullOrEmpty($RFname))
    {
        $WMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig"
    } else {
        $WMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicatedFolderName='" + $RFName + "'"
    }
    $WMIObject = Get-WmiObject -computername $computer -Namespace "root\MicrosoftDFS" -Query $WMIQuery
    Write-Output $WMIObject
    Write-Host "`nQuerying DFSR folders $WMIObject" -ForegroundColor Green
    Write-Output "`n$CurrentDate --> Querying DFSR folders $WMIObject" | Add-Content $LogFile
}
 
 
Function Get-DFSRBacklogInfo ($Computer, $RGroups, $RFolders, $RConnections)
{
   $objSet = @()
   
   Foreach ($Group in $RGroups)
   {
        $ReplicationGroupName = $Group.ReplicationGroupName    
        $ReplicationGroupGUID = $Group.ReplicationGroupGUID
           
        Foreach ($Folder in $RFolders) 
        {
           If ($Folder.ReplicationGroupGUID -eq $ReplicationGroupGUID) 
           {
                $ReplicatedFolderName = $Folder.ReplicatedFolderName
                $FolderEnabled = $Folder.Enabled
                Foreach ($Connection in $Rconnections)
                {
                    If ($Connection.ReplicationGroupGUID -eq $ReplicationGroupGUID) 
                    {    
                        $ConnectionEnabled = $Connection.Enabled
                        $BacklogCount = $Null
                        If ($FolderEnabled) 
                        {
                            If ($ConnectionEnabled)
                            {
                                If ($Connection.Inbound)
                                {
                                    #Write-Debug "Connection Is Inbound"
                                    #Write-Host "`nConnection Is Inbound" -ForegroundColor Green
                                    #Write-Output "`n$CurrentDate --> Connection Is Inbound" | Add-Content $LogFile
                                    $Smem = $Connection.PartnerName.Trim()
                                    #Write-Debug $smem
                                    #Write-Host "`n$Smem" -ForegroundColor Green
                                    #Write-Output "`n$CurrentDate --> $Smem" | Add-Content $LogFile 
                                    $Rmem = $Computer.ToUpper()
                                    #Write-Debug $Rmem
                                    #Write-Host "`n$Rmem" -ForegroundColor Green
                                    #Write-Output "`n$CurrentDate --> $Rmem" | Add-Content $LogFile 
                                    
                                    #Get the version vector of the inbound partner
                                    $WMIQuery = "SELECT * FROM DfsrReplicatedFolderInfo WHERE ReplicationGroupGUID = '" + $ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicatedFolderName + "'"
                                    $InboundPartnerWMI = Get-WmiObject -computername $Rmem -Namespace "root\MicrosoftDFS" -Query $WMIQuery
                                    
                                    $WMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID = '" + $ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicatedFolderName + "'"
                                    $PartnerFolderEnabledWMI = Get-WmiObject -computername $Smem -Namespace "root\MicrosoftDFS" -Query $WMIQuery
                                    $PartnerFolderEnabled = $PartnerFolderEnabledWMI.Enabled             
                                    
                                    If ($PartnerFolderEnabled)
                                    {
                                        $Vv = $InboundPartnerWMI.GetVersionVector().VersionVector
                                        
                                        #Get the backlogcount from outbound partner
                                        $WMIQuery = "SELECT * FROM DfsrReplicatedFolderInfo WHERE ReplicationGroupGUID = '" + $ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicatedFolderName + "'"
                                        $OutboundPartnerWMI = Get-WmiObject -computername $Smem -Namespace "root\MicrosoftDFS" -Query $WMIQuery
                                        $BacklogCount = $OutboundPartnerWMI.GetOutboundBacklogFileCount($Vv).BacklogFileCount  
                                    }
                                } else {
                                    #Write-Debug "Connection Is Outbound"
                                    #Write-Host "`nConnection Is Outbound" -ForegroundColor Green
                                    #Write-Output "`n$CurrentDate --> Connection Is Outbound" | Add-Content $LogFile 
                                    $Smem = $Computer.ToUpper()
                                    #Write-Host "`n$Smem" -ForegroundColor Green
                                    #Write-Output "`n$CurrentDate --> $Smem" | Add-Content $LogFile    
                                    #Write-Debug $smem                   
                                    $Rmem = $Connection.PartnerName.Trim()
                                    #Write-Debug $Rmem
                                    #Write-Host "`n$Rmem" -ForegroundColor Green
                                    #Write-Output "`n$CurrentDate --> $Rmem" | Add-Content $LogFile  
                                    
                                    #Get the version vector of the inbound partner
                                    $WMIQuery = "SELECT * FROM DfsrReplicatedFolderInfo WHERE ReplicationGroupGUID = '" + $ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicatedFolderName + "'"
                                    $InboundPartnerWMI = Get-WmiObject -computername $Rmem -Namespace "root\MicrosoftDFS" -Query $WMIQuery
                                    
                                    $WMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID = '" + $ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicatedFolderName + "'"
                                    $PartnerFolderEnabledWMI = Get-WmiObject -computername $Rmem -Namespace "root\MicrosoftDFS" -Query $WMIQuery
                                    $PartnerFolderEnabled = $PartnerFolderEnabledWMI.Enabled
                                    
                                    If ($PartnerFolderEnabled)
                                    {
                                        $Vv = $InboundPartnerWMI.GetVersionVector().VersionVector
                                        
                                        #Get the backlogcount from outbound partner
                                        $WMIQuery = "SELECT * FROM DfsrReplicatedFolderInfo WHERE ReplicationGroupGUID = '" + $ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicatedFolderName + "'"
                                        $OutboundPartnerWMI = Get-WmiObject -computername $Smem -Namespace "root\MicrosoftDFS" -Query $WMIQuery
                                        $BacklogCount = $OutboundPartnerWMI.GetOutboundBacklogFileCount($Vv).BacklogFileCount
                                    }              
                                }
                            }
                        }
                    
                        $obj = New-Object psobject
                        $obj | Add-Member noteproperty ReplicationGroupName $ReplicationGroupName
                        #write-debug $ReplicationGroupName
                        #Write-Host "`n$ReplicationGroupName" -ForegroundColor Green
                        #Write-Output "`n$CurrentDate --> $ReplicationGroupName" | Add-Content $LogFile  
                        $obj | Add-Member noteproperty ReplicatedFolderName $ReplicatedFolderName 
                        #write-debug $ReplicatedFolderName
                        #Write-Host "`n$ReplicatedFolderName" -ForegroundColor Green
                        #Write-Output "`n$CurrentDate --> $ReplicatedFolderName" | Add-Content $LogFile 
                        $obj | Add-Member noteproperty SendingMember $Smem
                        #write-debug $Smem
                        #Write-Host "`n$Smem" -ForegroundColor Green
                        #Write-Output "`n$CurrentDate --> $Smem" | Add-Content $LogFile  
                        $obj | Add-Member noteproperty ReceivingMember $Rmem$
                        #write-debug $Rmem
                        #Write-Host "`n$Rmem" -ForegroundColor Green
                        #Write-Output "`n$CurrentDate --> $Rmem" | Add-Content $LogFile  
                        $obj | Add-Member noteproperty BacklogCount $BacklogCount
                        #write-debug $BacklogCount
                        #Write-Host "`n$BacklogCount" -ForegroundColor Green
                        #Write-Output "`n$CurrentDate --> $BacklogCount" | Add-Content $LogFile  
                        $obj | Add-Member noteproperty FolderEnabled $FolderEnabled
                        #write-debug $FolderEnabled
                        #Write-Host "`n$FolderEnabled" -ForegroundColor Green
                        #Write-Output "`n$CurrentDate --> $FolderEnabled" | Add-Content $LogFile  
                        $obj | Add-Member noteproperty ConnectionEnabled $ConnectionEnabled
                        #write-debug $ConnectionEnabled
                        #Write-Host "`n$ConnectionEnabled" -ForegroundColor Green
                        #Write-Output "`n$CurrentDate --> $ConnectionEnabled" | Add-Content $LogFile  
                        $obj | Add-Member noteproperty Inbound $Connection.Inbound
                        #write-debug $Connection.Inbound
                        #Write-Host "`n"
                        #Write-Host $Connection.Inbound -ForegroundColor Green
                        #Write-Output "$CurrentDate --> " + $Connection.Inbound | Add-Content $LogFile
                        #Write-Output "`n" | Add-Content $LogFile  
                        
                        
                        If ($BacklogCount -ne $Null)
                        {
                            If ($BacklogCount -lt $WarningThreshold) 
                            {
                                $Backlogstatus = "Low"
                            }
                            elseif (($BacklogCount -ge $WarningThreshold) -and ($BacklogCount -lt $ErrorThreshold))
                            {
                                $Backlogstatus = "Warning"
                            }
                            elseif ($BacklogCount -ge $ErrorThreshold)
                            {
                                $Backlogstatus = "Error"
                            } 
                        } else {
                            $Backlogstatus = "Disabled"
                        }
                    
                        $obj | Add-Member noteproperty BacklogStatus $BacklogStatus
                    
                        $objSet += $obj
                    }
                }  
           } 
        }
   }
   Write-Output $objSet
   #Write-Host "`n"
   #Write-Host $objSet -ForegroundColor Green
   #Write-Output "$CurrentDate --> $objSet" | Add-Content $LogFile
   #Write-Output "`n" | Add-Content $LogFile 
}

#endregion

# This function reads an Integer8 Value from Active Directory and returns an object
# with LowPart and Highpart properties
function GetInteger8([Object] $Integer8)
{
    $gp = [Reflection.Bindingflags]::GetProperty
    $objType = $Integer8.GetType()
    $objValue = $objType.InvokeMember("Value", $gp, $null, $Integer8, $null)
    $objType = $objValue.GetType()
   
    $return = New-Object -TypeName System.Object
   
    $return | Add-Member -MemberType NoteProperty -Name LowPart -Value $objType.InvokeMember("LowPart", $gp, $null, $objValue, $null)
    $return | Add-Member -MemberType NoteProperty -Name HighPart -Value $objType.InvokeMember("HighPart", $gp, $null, $objValue, $null)
   
    return $return
}

# This function returns an object with all RID Data as properties
# Note that you need to bind to the domain controller you want data from
function GetRidData([System.DirectoryServices.DirectoryEntry] $RidSet)
{
    $objParent = New-Object System.DirectoryServices.DirectoryEntry($RidSet.Parent)
    [string]$dcName = $objParent.Name
   
    $return = New-Object -TypeName System.Object
    # Domain Controller (Netbios) name
    $return | Add-Member -MemberType NoteProperty -Name DC -Value $dcName

    # rIDAllocationPool is a 64 bit value, the lowpart being the From and the highpart the To
    $AllocPool = GetInteger8 $RidSet.rIDAllocationPool
    $return | Add-Member -MemberType NoteProperty -Name rIDAllocationPoolFrom -Value $AllocPool.LowPart
    $return | Add-Member -MemberType NoteProperty -Name rIDAllocationPoolTo -Value $AllocPool.HighPart
   
    # rIDPreviousPool is a 64 bit value, the lowpart being the From and the highpart the To
    $PrevPool = GetInteger8 $RidSet.rIDPreviousAllocationPool       
    $return | Add-Member -MemberType NoteProperty -Name rIDPreviousAllocationPoolFrom -Value $PrevPool.LowPart
    $return | Add-Member -MemberType NoteProperty -Name rIDPreviousAllocationPoolTo -Value $PrevPool.HighPart
   
    # rIDPreviousPool is an array with a single value
    $return | Add-Member -MemberType NoteProperty -Name rIDNextRID -Value $RidSet.rIDNextRID[0]
   
    return $return
}


Function Search-AD {
    param (           
        [string[]]$Filter,           
        [string[]]$Properties,           
        [string]$SearchRoot           
    )           
    if ($SearchRoot) {           
        $Root = [ADSI]$SearchRoot           
    } else {           
        $Root = [ADSI]''           
    }           
           
    if ($Filter)
    {           
        $LDAP = "(&({0}))" -f ($Filter -join ')(')           
    }
    else
    {           
        $LDAP = "(name=*)"           
    }           
           
    if (!$Properties)
    {           
        $Properties = 'Name','ADSPath'           
    }           
           
    (New-Object ADSISearcher -ArgumentList @(           
        $Root,           
        $LDAP,           
        $Properties           
    ) -Property @{           
        PageSize = 1000           
    }).FindAll() | ForEach-Object {           
        $ObjectProps = @{}           
        $_.Properties.GetEnumerator() |            
            Foreach-Object {           
                $ObjectProps.Add(           
                    $_.Name,            
                    (-join $_.Value)           
                )           
        }           
        New-Object PSObject -Property $ObjectProps |            
            select $Properties           
    }           
}

#endregion

#region "Variables"

CLS #Clear Screen

$ADConnected = $false
$schema = ""
$forest = ""
$schemapartition = ""
$RootDSC = ""
$DomNamingContext = ""
$ConfigNamingContext = ""
$GCs = ""
$GCNames = ""
$ForestDCs = ""
$ForestGCs = ""
           
$TimeVal = Get-Date -uformat "%Y-%m-%d-%H-%M"
$CurrentDate = Get-Date -Format d
$CurrentDay = (Get-Date).DayOfWeek.ToString()
$LogDir = "C:\Logs\"
$LogFileName = $CurrentDay + "_ReplLogs.txt"
$ADBackupReport = $CurrentDay + "_AD_BackupInfo.html"
$TopologyPic = $CurrentDay + "_CurrentTopologyDiagram.txt"
$TokenReport = $CurrentDay + "_CurrentKerberosTokenReport.csv"
$TokenReportPath = $LogDir + $TokenReport
$TopologyPicPath = $LogDir + $TopologyPic
$HtmlPath = $LogDir + $ADBackupReport
$LogFile = $LogDir + $LogFileName
$CurrentScriptVersion = "3.0"

Write-Host "`nSetting LogPath to $LogDir" -ForegroundColor Green
IF (!(Test-Path $LogDir)) {new-item -type Directory -path $LogDir} 

Write-Output "********************************************************************** Logging Started *******************************************************************************************************" | Add-Content $LogFile

#endregion

#region "Author Information

Write-Host "                                                 --> Active Directory Replication Tool <--                                " -ForeGroundColor Magenta
Write-Host "                                                                                                                           " -ForeGroundColor Magenta
Write-Host "                                                 The script is as a wrapper for ReplAdmin functions                       " -ForeGroundColor Magenta
Write-Host "                                                 Using Powershell to check replication status of the current forest       " -ForeGroundColor Magenta
Write-Host "                                                                                                                          " -ForeGroundColor Magenta
Write-Host "                                                 Written by: Michael Aksoy                                                  " -ForeGroundColor Magenta
Write-Host "                                                 Dimension Data Pty Ltd                                                      " -ForeGroundColor Magenta
Write-Host "                                                 Design Engineer/Engineer                                                 " -ForeGroundColor Magenta
Write-Host "                                                                                                                          " -ForeGroundColor Magenta   
Write-Host "`n"
Write-Host "`n"




Write-Output "                                                 --> Active Directory Replication Tool <--                                " | Add-Content $LogFile
Write-Output "                                                                                                                             " | Add-Content $LogFile
Write-Output "                                                 The script is as a wrapper for ReplAdmin functions                       " | Add-Content $LogFile
Write-Output "                                                 Using Powershell to check replication status of the current forest       " | Add-Content $LogFile
Write-Output "                                                                                                                          " | Add-Content $LogFile
Write-Output "                                                 Written by: Michael Aksoy                                                " | Add-Content $LogFile
Write-Output "                                                 Dimension Data Pty Ltd                                                    " | Add-Content $LogFile
Write-Output "                                                 Design Engineer/Engineer                                                 " | Add-Content $LogFile
Write-Output "`n"
Write-Output "`n"
Write-Output "`n"

#endregion

#region "Topology Replication"

if($ReplicateTopology -eq $true)
{
     Write-Output "`n" | Add-Content $LogFile
     Write-Output "`n" | Add-Content $LogFile
     Write-Host "`n============================================ Topology Replication ===================================================================" -ForegroundColor Magenta
     Write-Output "`n============================================ Topology Replication ===================================================================" | Add-Content $LogFile
 
#region "Repadmin /syncall switches"

    <#
      Replication Parameters
     
      
        Force AD synchronization

        repadmin /syncall  - Force AD synchronization

        repadmin /syncall /P - Force AD synchronization (Push mode)

        General using:

        repadmin /SyncAll [/Switches]  []

        Switches:

         /a: Abort if any server is unavailable
         /A: Perform /SyncAll for all NC's held by  (ignores ) (All Partitions)
         /d: ID servers by DN in messages (instead of GUID DNS) (distingusihed names)
         /e: Enterprise, cross sites (default: only home site)
         /h: Print this help screen
         /i: Iterate indefinitely
         /I: Perform showreps on each server pair in path instead of syncing
         /j: Sync adjacent servers only
         /p: Pause for possible user abort after every message
         /P: Push changes outward from home server (default: pull changes)
         /q: Quiet mode, suppress callback messages
         /Q: Very quiet, report fatal errors only
         /s: Do not sync (just analyze topology and generate messages)
         /S: Skip initial server-response check (assume all servers are available)
        If  is omitted DsReplicaSyncAll defaults to the Configuration NC.


        Example :

        repadmin /syncall /A /P /e /d

    #>

#endregion

 try{
    #Connect to AD
    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
    Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
    $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
    $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
    $forestName = $forest.Name
    $domainName = $forest.Domains | Out-String
    $schemapartition = $schema.Name
    $RootDSC = [adsi]"LDAP://RootDSE"
    $DomNamingContext = $RootDSC.RootDomainNamingContext
    $ConfigNamingContext = $RootDSC.configurationNamingContext
    $ADConnected = $true
   
    Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
    Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

   
    if($ADConnected)
    {
        Write-Host ""

        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

        Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
        Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
        Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
        Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
        Write-Host ""

        Write-Output "`n" | Add-Content $LogFile

        Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

        $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
        Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
        $GCs | FT -AutoSize
        Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
        $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

        $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

        $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
        Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
        $ForestDCs | FT -AutoSize
        Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
        $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
        $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

        ForEach($GCName in $ForestGCs)
        {
            $tmpGC = $GCName.Name
            Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
            Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
            Write-Host "Replicating Topology to $tmpGC" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Replicating Topology to $tmpGC" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile

            $cmdRepToplogy = "RepAdmin /kcc $tmpGC"
            Write-Host "`nExecuting RepAdmin command $cmdRepToplogy" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdRepToplogy" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile

            Invoke-Expression -Command $cmdRepToplogy
            Invoke-Expression $cmdRepToplogy | Out-String | Add-Content $LogFile
           
            #initiate the replication
            Write-Host "Initiating AD Synchronisation on $tmpGC" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Initiating AD Synchronisation on $tmpGC" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile

            $cmdStartRep = "RepAdmin /syncall /A /P /e /d $tmpGC"
            Write-Host "`nExecuting RepAdmin command $cmdStartRep" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdStartRep" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile

            Invoke-Expression -Command $cmdStartRep
            Invoke-Expression $cmdStartRep | Out-String | Add-Content $LogFile
        }
   
     }

   }
   catch [Exception]
   {
        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Exit
   }

   Write-Host "`n============================================ Finished: Topology Replication ===================================================================" -ForegroundColor Magenta
   Write-Output "`n============================================ Finished: Topology Replication ===================================================================" | Add-Content $LogFile
   Write-Output "`n" | Add-Content $LogFile

}

#endregion

#region "Check Replication Topology"

if($CheckReplicationTopology -eq $true)
{
     Write-Output "`n" | Add-Content $LogFile
     Write-Output "`n" | Add-Content $LogFile
     Write-Host "`n============================================ Checking Replication Topology ===================================================================" -ForegroundColor Magenta
     Write-Output "`n============================================ Checking Replication Topology ===================================================================" | Add-Content $LogFile
 
#region "Repadmin /syncall switches"

    <#
      Replication Parameters
     
      
        Force AD synchronization

        repadmin /syncall  - Force AD synchronization

        repadmin /syncall /P - Force AD synchronization (Push mode)

        General using:

        repadmin /SyncAll [/Switches]  []

        Switches:

         /a: Abort if any server is unavailable
         /A: Perform /SyncAll for all NC's held by  (ignores )
         /d: ID servers by DN in messages (instead of GUID DNS)
         /e: Enterprise, cross sites (default: only home site)
         /h: Print this help screen
         /i: Iterate indefinitely
         /I: Perform showreps on each server pair in path instead of syncing
         /j: Sync adjacent servers only
         /p: Pause for possible user abort after every message
         /P: Push changes outward from home server (default: pull changes)
         /q: Quiet mode, suppress callback messages
         /Q: Very quiet, report fatal errors only
         /s: Do not sync (just analyze topology and generate messages)
         /S: Skip initial server-response check (assume all servers are available)
        If  is omitted DsReplicaSyncAll defaults to the Configuration NC.


        Example :

        repadmin /syncall /e /A /P

    #>

#endregion

 try{
    #Connect to AD
    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
    Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
    $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
    $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
    $forestName = $forest.Name
    $domainName = $forest.Domains | Out-String
    $schemapartition = $schema.Name
    $RootDSC = [adsi]"LDAP://RootDSE"
    $DomNamingContext = $RootDSC.RootDomainNamingContext
    $ConfigNamingContext = $RootDSC.configurationNamingContext
    $ADConnected = $true
   
    Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
    Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

   
    if($ADConnected)
    {
        Write-Host ""

        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

        Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
        Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
        Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
        Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
        Write-Host ""

        Write-Output "`n" | Add-Content $LogFile

        Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

        $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
        Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
        $GCs | FT -AutoSize
        Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
        $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

        $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

        $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
        Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
        $ForestDCs | FT -AutoSize
        Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
        $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
        $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

        ForEach($GCName in $ForestGCs)
        {
            $tmpGC = $GCName.Name
            Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
            Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
            Write-Host "Checking Replication Topology on $tmpGC" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Checking Replication Topology on $tmpGC" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile

            $cmdRepToplogy = "RepAdmin /kcc $tmpGC"
            Write-Host "`nExecuting RepAdmin command $cmdRepToplogy" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdRepToplogy" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile

            Invoke-Expression -Command $cmdRepToplogy
            Invoke-Expression $cmdRepToplogy | Out-String | Add-Content $LogFile
           
         }
   
     }

   }
   catch [Exception]
   {
        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit
   }

    Write-Host "`n============================================ Finished: Checking Replication Topology ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Checking Replication Topology ===================================================================" | Add-Content $LogFile
 
}

#endregion

#region "Display Server Connections"

if($GetServerConnections)
{
     Write-Output "`n" | Add-Content $LogFile
     Write-Output "`n" | Add-Content $LogFile
     Write-Host "`n============================================ Display Active Directory Connections ===================================================================" -ForegroundColor Magenta
     Write-Output "`n============================================ Display Active Directory Connections ===================================================================" | Add-Content $LogFile
       
    try
    {

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

            Write-Host ""

            Write-Output "`n" | Add-Content $LogFile
            Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

            Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
            Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
            Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
            Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
            Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
            Write-Host ""

            Write-Output "`n" | Add-Content $LogFile

            Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

            $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
            Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
            $GCs | FT -AutoSize
            Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
            $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

            $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

            $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
            Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
            $ForestDCs | FT -AutoSize
            Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
            $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
            $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

            ForEach($GCName in $ForestGCs)
            {
                $tmpGC = $GCName.Name
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Displaying Active Directory Connections to Domain Controller/Global Catalogue Server $tmpGC" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Displaying Active Directory Connections to Domain Controller/Global Catalogue Server $tmpGC" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdShowConn = "RepAdmin /ShowConn $tmpGC"
                Write-Host "`nExecuting RepAdmin command $cmdShowConn" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowConn" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Invoke-Expression -Command $cmdShowConn
                Invoke-Expression $cmdShowConn | Out-String | Add-Content $LogFile
           

            }
        }

    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Exit

    }
 
   Write-Host "`n============================================ Finished: Display Active Directory Connections ===================================================================" -ForegroundColor Magenta
   Write-Output "`n============================================ Finished: Active Directory Connections ===================================================================" | Add-Content $LogFile
   Write-Output "`n" | Add-Content $LogFile
   
}

#endregion

#region "Display Replication Signature"

if($GetSignatures)
{
   
    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Display Replication Signature ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Display Replication Signature ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

                ForEach($GCName in $ForestGCs)
                {
                    $tmpGC = $GCName.Name
                    Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                    Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                    Write-Host "Display Replication Signature for Server $tmpGC" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Display Replication Signature for Server $tmpGC" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    $cmdShowSig = "RepAdmin /ShowSig $tmpGC"
                    Write-Host "`nExecuting RepAdmin command $cmdShowSig" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowSig" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    Invoke-Expression -Command $cmdShowSig
                    Invoke-Expression $cmdShowSig | Out-String | Add-Content $LogFile
           

                }

        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Display Replication Signature ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Display Replication Signature ===================================================================" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile

}


#endregion

#region Display Context Handles of Replication Process"

if($GetHandles)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Display Context Handles for Replication Process ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Display Context Handles for Replication Process ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

                ForEach($GCName in $ForestGCs)
                {
                    $tmpGC = $GCName.Name
                    Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                    Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                    Write-Host "Displaying Context Handles for Replication Process for server $tmpGC" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Displaying Context Handles for Replication Process for server $tmpGC" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    $cmdShowCtx = "RepAdmin /ShowCtx $tmpGC"
                    Write-Host "`nExecuting RepAdmin command $cmdShowCtx" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowCtx" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    Invoke-Expression -Command $cmdShowCtx
                    Invoke-Expression $cmdShowCtx | Out-String | Add-Content $LogFile
           

                }

        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Display Context Handles for Replication Process ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Display Context Handles for Replication Process ===================================================================" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile

}

#endregion

#region "Get the Highest Update Sequence Number (USN) on a Domain Controller"

if($GetUSN)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Display the highest Update Sequence Number (USN) on a Domain Controller ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Display the highest Update Sequence Number (USN) on a Domain Controller ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

                ForEach($GCName in $ForestGCs)
                {
                    $tmpGC = $GCName.Name -split "\."
                    $ServerName = $tmpGC[0]
                    $NameContext = "'" + $DomNamingContext + "'"
                    Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                    Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                    Write-Host "Displaying the highest Update Sequence Number (USN) on a Domain Controller/Global Catalogue Server $ServerName" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Displaying the highest Update Sequence Number (USN) on a Domain Controller/Global Catalogue Server $ServerName" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    #Example: repadmin /showutdvec SVADC-2NSI-0501NP dc=nbntest,dc=local
                    $cmdShowUSN = "RepAdmin /showutdvec $ServerName $NameContext"
                    Write-Host "`nExecuting RepAdmin command $cmdShowUSN" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowUSN" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    Invoke-Expression -Command $cmdShowUSN
                    Invoke-Expression $cmdShowUSN | Out-String | Add-Content $LogFile
           

                }

        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Display the highest Update Sequence Number (USN) on a Domain Controller ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Display the highest Update Sequence Number (USN) on a Domain Controller ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Get Un-Replicated Changes"

if($GetUnReplicatedChanges)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Summarise UnReplicated Changes ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Summarise UnReplicated Changes ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

                ForEach($GCName in $ForestGCs)
                {
                    $tmpGC = $GCName.Name -split "\."
                    $ServerName = $tmpGC[0]
                    $NameContext = "'" + $ConfigNamingContext + "'"
                    Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                    Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                    Write-Host "Displaying Summary of UnReplicated Changes for Server $ServerName" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Displaying Summary of UnReplicated Changes for Server $ServerName" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    $cmdShowChanges = "RepAdmin /showchanges $ServerName $NameContext /statistics"
                    Write-Host "`nExecuting RepAdmin command $cmdShowChanges" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowChanges" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    Invoke-Expression -Command $cmdShowChanges
                    Invoke-Expression $cmdShowChanges | Out-String | Add-Content $LogFile

                    Write-Host "`n***NOTE*** If the command outputs 'NO Changes' then all the replica partners are in Sync" -ForegroundColor White
                    Write-Output "`n$CurrentDate --> ***NOTE*** If the command outputs 'NO Changes' then all the replica partners are in Sync" | Add-Content $LogFile
           

                }

        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Summarise UnReplicated Changes ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Summarise UnReplicated Changes ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Get Failed Replications"

if($GetFailedReplications)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Display Failed Replications ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Display Failed Replications ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

                ForEach($GCName in $ForestGCs)
                {
                    $tmpGC = $GCName.Name -split "\."
                    $ServerName = $tmpGC[0]
                    Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                    Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                    Write-Host "Displaying Failed Replications for Server $ServerName" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Displaying Failed Replications for Server $ServerName" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    $cmdShowFailedReps = "RepAdmin /FailCache $ServerName"
                    Write-Host "`nExecuting RepAdmin command $cmdShowFailedReps" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowFailedReps" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    Invoke-Expression -Command $cmdShowFailedReps
                    Invoke-Expression $cmdShowFailedReps | Out-String | Add-Content $LogFile
           

                }

        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Failed Replications ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Failed Replications ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Show Replication Status"

if($ShowReplicationStatus)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Show Replication Status ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Show Replication Status ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Displaying Replication Status" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Displaying Replication Status" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdRepStatus = "RepAdmin /ShowRepl * /csv"
                Write-Host "`nExecuting RepAdmin command $cmdRepStatus" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdRepStatus" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                #$RepStatusOutPut = ConvertFrom-Csv -InputObject $cmdRepStatus | where {$_.'Number of Failures' -ge 1}
                $RepStatusOutPut = Invoke-Expression $cmdRepStatus
                $CsvOutPut = ConvertFrom-CSV $RepStatusOutPut | where {$_.'Number of Failures' -ge 1}
                $CommonOutPut = ConvertFrom-CSV $RepStatusOutPut

                $results = $CsvOutPut | where {$_.'Number of Failures' -gt 1 }

                if($results -ne $null)
                {
                    Write-Host "`nCurrent replication Issues" -ForegroundColor Yellow
                    Write-Output "`n$CurrentDate --> Current replication Issues" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile
                    $CurrentRepStatus = $results | select "Source DSA", "Naming Context", "Destination DSA" ,"Number of Failures", "Last Failure Time", "Last Success Time", "Last Failure Status" | FT -AutoSize
                }else{

                    Write-Host "`nThere are no Replication Issues" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> There are no Replication Issues" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    $CommonOutPut | FT -AutoSize
                    $CommonOutPut | FT -AutoSize | Out-String | Add-Content $LogFile
                }

                #Invoke-Expression $cmdRepStatus | Out-String | Add-Content $LogFile

               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Show Replication Status ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Show Replication Status ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Replication Summary"

if($SummariseReplicationStatus)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Replication Summary ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Replication Summary ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

               
                Write-Output "`n" | Add-Content $LogFile
                Write-Host "Displaying Replication Overall Summary" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Displaying Replication Overall Summary" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdRepSummary = "RepAdmin /replsum * /bysrc /bydest /sort:delta"
                Write-Host "`nExecuting RepAdmin command $cmdRepSummary" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdRepSummary" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $CurrentRepInfo = Invoke-Expression -Command $cmdRepSummary

                #Clean Up the ReplSum information
                $CleanRepInfo = @()
                # Start @ #10 because all the previous lines are junk formatting
                # and strip off the last 4 lines because they are not needed.
                for ($i=10; $i -lt ($CurrentRepInfo.Count-4); $i++) {
                     if($CurrentRepInfo[$i] -ne ""){
                        # Remove empty lines from our array.
                        $CurrentRepInfo[$i] -replace '\s+', " "          
                        $CleanRepInfo += $CurrentRepInfo[$i]           
                     }
                }

                $finalRepInfo = @() #Last Formatting

                #Format Probably to display need output i.e. readable output
                Write-Host "`nFormatting Output of ReplSum....Please be patient!" -ForegroundColor Cyan
                Write-Output "`n$CurrentDate --> Formatting Output of ReplSum....Please be patient!" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile
                 ForEach ($line in $cleanRepInfo) {

                    $splitRepInfo = $line -split '\s+',8
                    if ($splitRepInfo[0] -eq "Source") { $repType = "Source" }
                    if ($splitRepInfo[0] -eq "Destination") { $repType = "Destination" }

                     if ($splitRepInfo[1] -notmatch "DSA") {     
                       # Create an Object and populate it with our values.
                       $objRepValues = New-Object System.Object
                       $objRepValues | Add-Member -type NoteProperty -name DSAType -value $repType # Source or Destination DSA
                       $objRepValues | Add-Member -type NoteProperty -name Hostname  -value $splitRepInfo[1] # Hostname
                       $objRepValues | Add-Member -type NoteProperty -name Delta  -value $splitRepInfo[2] # Largest Delta
                       $objRepValues | Add-Member -type NoteProperty -name Fails -value $splitRepInfo[3] # Failures
                       #$objRepValues | Add-Member -type NoteProperty -name Slash  -value $splitRepInfo[4] # Slash char
                       $objRepValues | Add-Member -type NoteProperty -name Total -value $splitRepInfo[5] # Totals
                       $objRepValues | Add-Member -type NoteProperty -name PctError  -value $splitRepInfo[6] # % errors 
                       $objRepValues | Add-Member -type NoteProperty -name ErrorMsg  -value $splitRepInfo[7] # Error code
         
                       # Add the Object as a row to our array  
                       $finalRepInfo += $objRepValues
          
                    }

                 }

                 $ReplSumErrors = $finalRepInfo | Where {$_.'Fails' -gt 0 }
                 $finalRepInfo | FT -AutoSize
                 $finalRepInfo | FT -AutoSize | Out-String | Add-Content $LogFile

                 if($ReplSumErrors -ne $null)
                 {
                    Write-Host "`nReplication Errors have been found" -ForegroundColor Yellow
                    Write-Output "`n$CurrentDate --> Replication Errors have been found" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    $ReplSumErrors | FT -AutoSize
                    $ReplSumErrors | FT -AutoSize | Out-String | Add-Content $LogFile

                 }else{
                   
                    Write-Host "`nThere are no Replication Errors!" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> here are no Replication Errors!" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                 }
                                 
                #Invoke-Expression $cmdRepSummary | Out-String | Add-Content $LogFile

        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Replication Summary ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Replication Summary ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Get Last Backup of Active Directory"

if($ShowLastBackupStatus)
{

    <#
    NOTE:
    When Active Directory is backed up, the backup causes the DSA Signature attribute to be updated.
    However it doesn't tell you if th backup was successfull or not. The script will nicely format the output
    into a readable html output

    #>

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Display Active Directory Backup Information ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Display Active Directory Backup Information ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

                Write-Output "`n" | Add-Content $LogFile
                Write-Host "Displaying Active Directory Backup Status" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Displaying Active Directory Backup Status" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdShowBackup = "RepAdmin /showbackup  *"
                Write-Host "`nExecuting RepAdmin command $cmdShowBackup" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowBackup" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

               

                $Report = Invoke-Expression -Command $cmdShowBackup

                Write-Host "`n***NOTE*** The output will be formatted in a Html File. Location will be in $HtmlPath" -ForegroundColor Cyan
                Write-Output "`n$CurrentDate --> ***NOTE*** The output will be formatted in a Html File. Location will be in $HtmlPath" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                #region "Backup Report HTML Format"

                #NOTE: Formatting Reference --> http://gallery.technet.microsoft.com/scriptcenter/Monitor-Active-Directory-f420fa39 (Active Directory Backup)
               
                $date = Get-Date -Format "yyyy-MM-dd"

                $BackupCount = 0

                $FinalADBackupReport = "<HTML><HEAD>
                                    <style type='text/css'>
                                    table.tftable {font-family:verdana,arial,sans-serif;font-size:12px;color:#333333;border-width: 1px;border-color: #729ea5;border-collapse: collapse;}
                                    table.tftable th {font-family:verdana,arial,sans-serif;font-size:12px;background-color:#acc8cc;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;text-align:left;}
                                    table.tftable tr {font-family:verdana,arial,sans-serif;background-color:#d4e3e5;}
                                    table.tftable td {font-family:verdana,arial,sans-serif;font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;}
                                    </style><h3>Active Directory Backup Information: " + $CurrentDate + "<h3>
                                    </HEAD><body>"
               
                $BackupOk = @()
                $BackupOk += "<table class='tftable' border='1'><tr><th><p>Domain</p></th><th><p>Hostname</p></th><th><p>AD Partition</p></th><th><p>Last backup</p></th></tr>"
                $Backup_ko = "<table class='tftable' border='1'><tr><th><p>Hostname</p></th><th><p>AD Partition</p></th><th><p>Last backup</p></th></tr>"
                $Backup_error = "<table class='tftable' border='1'><tr><th><p>Hostname</p></th><th><p>Error message</p></th></tr>"

                foreach ($line in $Report) {
                    if ($line -ne "") {
                        if ($line -like "Repadmin: *") {
                            $fqdn = $line.Split(" ")[-1]
                        }
                        if ($line -like "*dSASignature") {
                            $index = [array]::IndexOf($Report, $line)
                            if ($line -like "*dSASignature") {
                                $zone = $Report[($index-2)]
                            }
                            $backup_date = $line.Split(" ",[StringSplitOptions]'RemoveEmptyEntries')[3]
                            $BackupCount++
                            $diff = ((Get-Date $date) - (Get-Date $backup_date)).days
            
                            if ($diff -lt 2) {
                                $Hostname = $fqdn.split(".")[0]
                                $Domain = $fqdn.split(".")[1..(($fqdn.length) -1)] -join "."
                                $BackupOk += "<tr><td><p><font color=green>" + $Domain + "</p></td><td><p>" + $Hostname + "</p></td><td><p>" + $zone + "</p></td><td><p>" + $backup_date + "</p></td></tr>"
                            }
                            else {
                                $Backup_ko += "<tr><td><font color=red>" + $fqdn + "<td>" + $zone + "<td>" + $backup_date
                            }
                        }
                        if ($line -like "*error*") {
                            $Backup_error += "<tr><td><font color=red>" + $fqdn + "<td>" + $line
                        }
                    }
                }
 
               
                $BackupOk = $BackupOk | sort
               
                $footer = "Script Version $CurrentScriptVersion run {0}" -f (Get-Date)
                if($BackupCount -eq 0) #No Backups Exist
                {
                    if ($Backup_ko -eq "<table class='tftable' border='1'><tr><th><p>Hostname</p></th><th><p>AD Partition</p></th><th><p>Last backup</p></th></tr>") {
                        $Backup_ko = "<table style='color:yellow;font-family:verdana,arial,sans-serif;font-size:11px;'>Active Directory hasn't been backed up. Please back up Active Directory!!</table>"
                    }

                }else{
                    if ($Backup_ko -eq "<table class='tftable' border='1'><tr><th><p>Hostname</p></th><th><p>AD Partition</p></th><th><p>Last backup</p></th></tr>") {
                        $Backup_ko = "<table style='color:green;font-family:verdana,arial,sans-serif;font-size:11px;'>No problem detected</table>"
                    }
                }
                $subject = "Active Directory backup status : "+$date
                $FinalADBackupReport += "<font face='Calibri' color='black'><i><b>AD backup problem (more than 2 days) :</b></i><br>" + `
                            $Backup_ko + "</table><br>" + `
                            "<font face='Calibri' color='black'><i><b>Problem to contact the following domain controller(s) :</b></i><br>" + `
                            $Backup_error + "</table><br>" + `
                            "<font face='Calibri' color='black'><i><b>AD backup OK :</b></i><br>" + `
                            $BackupOk + "</table><br></body><br><I>" + $footer + "</I>"
               
                IF ((Test-Path $HtmlPath)) {Remove-Item $HtmlPath} #Remove the Html report before generating a new one.

                $FinalADBackupReport | Add-Content $HtmlPath

                Write-Host "`nAD Backup Report has been completed. Check $HtmlPath for report details." -ForegroundColor Cyan
                Write-Output "`n$CurrentDate --> AD Backup Report has been completed. Check $HtmlPath for report details." | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`n***NOTE*** The script will not report on any backup failures. Any backup failures relating to Active Directory, you will need investigate it from your back up software." -ForegroundColor White
                Write-Host "`n***NOTE*** If a domain controller is unavailable during the data collection, the script will report on this error." -ForegroundColor White
               
                Write-Output "`n$CurrentDate --> ***NOTE*** The script will not report on any backup failures. Any backup failures relating to Active Directory, you will need investigate it from your back up software." | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> ***NOTE*** If a domain controller is unavailable during the data collection, the script will report on this error." | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                #Launch the Html File

                Invoke-Item $HtmlPath

                #endregion

        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Display Active Directory Backup Information ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Display Active Directory Backup Information ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Check AD Replication Queue"

if($CheckReplicationBackLog)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Checking Active Directory Replication Queue (Backlog) ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Checking Active Directory Replication Queue (Backlog) ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest


                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Displaying Current Active Directory Replication Queue (BackLog)" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Displaying Current Active Directory Replication Queue (BackLog)" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdShowQueue = "RepAdmin /Queue *"
                Write-Host "`nExecuting RepAdmin command $cmdShowQueue" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowQueue" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Invoke-Expression -Command $cmdShowQueue
                Invoke-Expression $cmdShowQueue | Out-String | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Checking Active Directory Replication Queue (Backlog) ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Checking Active Directory Replication Queue (Backlog) ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "List the Topology information of all the Bridgehead Servers"

if($GetBridgeHeadServersInfo)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Get All Bridgehead Server Information ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Get All Bridgehead Server Information ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest


                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Showing Topology Information on All Bridgehead Servers" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Showing Topology Information on All Bridgehead Servers" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdShowBridgeHead = "RepAdmin /bridgeheads * /verbose"
                Write-Host "`nExecuting RepAdmin command $cmdShowBridgeHead" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowBridgeHead" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Invoke-Expression -Command $cmdShowBridgeHead
                Invoke-Expression $cmdShowBridgeHead | Out-String | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Get All Bridgehead Server Information ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Get All Bridgehead Server Information ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Displays calls that have not yet been answered, made by the specified server to other servers"

if($GetAllOutCalls)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Displaying Active Directory OutCalls ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Displaying Active Directory OutCalls ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest


                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Showing OutCalls, which have not been answered yet" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Showing OutCalls, which have not been answered yet" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdShowOutCalls = "RepAdmin /showoutcalls *"
                Write-Host "`nExecuting RepAdmin command $cmdShowOutCalls" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdShowOutCalls" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Invoke-Expression -Command $cmdShowOutCalls
                Invoke-Expression $cmdShowOutCalls | Out-String | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Displaying Active Directory OutCalls ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Displaying Active Directory OutCalls ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Inter Site Topology Generator Report"

if($GetISTGReport)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Generating Inter Site Topology Generator (ISTG) Report ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Generating Inter Site Topology Generator (ISTG) Report ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest


                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Generating ISTG Report...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Generating ISTG Report...." | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdISTG = "RepAdmin /istg * /verbose"
                Write-Host "`nExecuting RepAdmin command $cmdISTG" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdISTG" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Invoke-Expression -Command $cmdISTG
                Invoke-Expression $cmdISTG | Out-String | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Generating Inter Site Topology Generator (ISTG) Report ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Generating Inter Site Topology Generator (ISTG) Report ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Lists all domains trusted by a specified domain"

if($ShowAllTrusts)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Displaying Domain Trusts ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Displaying Domain Trusts ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest


                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Collecting All Domain Trusts...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Domain Trusts...." | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdTrusts = "RepAdmin /showtrust *"
                Write-Host "`nExecuting RepAdmin command $cmdTrusts" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdTrusts" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Invoke-Expression -Command $cmdTrusts
                Invoke-Expression $cmdTrusts | Out-String | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Displaying Domain Trusts ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Displaying Domain Trusts ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Show Replication Latency"

if($ShowRepLatency)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Displaying Replication Latency ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Displaying Replication Latency ===================================================================" | Add-Content $LogFile
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                $GCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest


                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Displaying Current Replication Latency" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Displaying Current Replication Latency" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdRepLatency = "RepAdmin /latency /verbose"
                Write-Host "`nExecuting RepAdmin command $cmdRepLatency" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing RepAdmin command $cmdRepLatency" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                Invoke-Expression -Command $cmdRepLatency
                Invoke-Expression $cmdRepLatency | Out-String | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Displaying Replication Latency ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Displaying Replication Latency ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Monitor NTP"

if($MonitorNTP)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Monitoring NTP ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Monitoring NTP ===================================================================" | Add-Content $LogFile
    $FinalNtpOutPut = @()
  

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile

                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
                Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> List of Domains in the AD Forest" | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                Write-Output "`n" | Add-Content $LogFile

                Write-Host "`nCollecting All Global Catalogue Servers...." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting All Global Catalogue Servers...." | Add-Content $LogFile

                $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
                Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
                #$GCs |Select-Object Forest, Name, CurrentTime, HighestCommittedUsn, OSVersion, Roles, Domain | FT -AutoSize
                $GCs |Select-Object Name, HighestCommittedUsn, Roles, Domain, IPAddress, SiteName | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
                #$GCs |Select-Object Forest, Name, CurrentTime, HighestCommittedUsn, OSVersion, Roles, Domain | FT -AutoSize | Out-String | Add-Content $LogFile
                $GCs |Select-Object Name, HighestCommittedUsn, Roles, Domain, IPAddress, SiteName | FT -AutoSize | Out-String | Add-Content $LogFile

                $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

                $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
                Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
                $ForestDCs | FT -AutoSize
                Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
                $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
                $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest


                Write-Output "`n----------------------------------------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
                Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan

     
                Write-Host "Monitoring/Checking NTP" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Monitoring/Checking NTP" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile
                $stdOutStart = 8

                # Time across all DC's should be compared agains the PDC Owner
                # Lets find Our PDC in our Forest

                $tmpPdcOwnerDC = $forest.Domains.pdcRoleOwner.Name -split "\."
                $PdcOwnerDC = $tmpPdcOwnerDC[0]

                Write-Host "Monitoring/Checking Time on PDC $PdcOwnerDC" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Monitoring/Checking Time on PDC $PdcOwnerDC" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $cmdMonNtpPdc = "w32tm /monitor /computers:$PdcOwnerDC"
                Write-Host "`nCollecting NTP Information for PDC $PdcOwnerDC" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Collecting NTP Information for PDC $PdcOwnerDC" | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                $NtpOutPutPdc = Invoke-Expression $cmdMonNtpPdc
                #Invoke-Expression $cmdMonNtp | Out-String | Add-Content $LogFile
                Write-Output "`n" | Add-Content $LogFile

                For($i = 0; $i -lt $NtpOutPutPdc.Length; $i++)
                     {
                           
                       if($i -eq 2)
                        {
                           #strip of Stratum Info
                           $tmpStrat = $NtpOutPutPdc[$i] -split "\:"
                           $Stratum = $tmpStrat[1]
                         }

                            if($i -eq 12)
                            {
                                $tmpICMP = $NtpOutPutPdc[$i] -split "\:"
                                $icmp = $tmpICMP[1]
                               
                            }

                            if($i -eq 13)
                            {
                                $tmp = $NtpOutPutPdc[$i] -split "\:"
                                $tmp2 = $tmp[1] -replace "RefID", ""
                                $ntpOffsetPDC = $tmp2 -replace " ", ""
                                $tmp3 = $tmp[2]
                                $refid = $tmp3
                               
                            }
                          
                     }

                 $tmpSPDC = $ntpOffsetPDC -replace "s",""

                ForEach($DC in $ForestDCs)
                {
                    $DCName = $DC.Name
                    $cmdMonNtp = "w32tm /monitor /computers:$DCName"
                    Write-Host "`nCollecting NTP Information for Domain Controller $DCName" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Collecting NTP Information for Domain Controller $DCName" | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile

                    $NtpOutPut = Invoke-Expression $cmdMonNtp
                    #Invoke-Expression $cmdMonNtp | Out-String | Add-Content $LogFile
                    Write-Output "`n" | Add-Content $LogFile
                  
                    if($NtpOutPut -ne $null)
                    {
                        For($i = 0; $i -lt $NtpOutPut.Length; $i++)
                        {
                           
                            if($i -eq 2)
                            {
                                #strip of Stratum Info
                                $tmpStrat = $NtpOutPut[$i] -split "\:"
                                $Stratum = $tmpStrat[1]
                            }

                            if($i -eq 12)
                            {
                                $tmpICMP = $NtpOutPut[$i] -split "\:"
                                $icmp = $tmpICMP[1]
                               
                            }

                            if($i -eq 13)
                            {
                                $tmp = $NtpOutPut[$i] -split "\:"
                                $tmp2 = $tmp[1] -replace "RefID", ""
                                $ntpOffset = $tmp2 -replace " ", ""
                                $tmp3 = $tmp[2]
                                $refid = $tmp3
                               
                            }
                          
                        }
                        $tmpS = $ntpOffset -replace "s",""
                        $pdcTime = New-TimeSpan -Seconds $tmpSPDC
                        $dcTime = New-TimeSpan -Seconds $tmpS
                        $tmpDiff = $pdcTime.Subtract($dcTime).TotalSeconds
                        $Diff = New-TimeSpan -Seconds $tmpDiff #Time difference Against PDC
                        if($Diff.TotalSeconds -gt 10)
                        {
                            $timeError = "Off by more than 10 Seconds"

                        }else{
                            $timeError ="Status OK"

                        }
                        $objRepValues = New-Object System.Object
                        $objRepValues | Add-Member -type NoteProperty -name DomainController -value $DCName # Domain Controller Name
                        $objRepValues | Add-Member -type NoteProperty -name ICMP  -value $icmp # ICMP (delay in ms)
                        $objRepValues | Add-Member -type NoteProperty -name NTPOffset  -value $ntpOffset # NTP Information including offset
                        $objRepValues | Add-Member -type NoteProperty -name TimeDiff  -value $Diff.TotalSeconds # Time Difference against PDC
                        $objRepValues | Add-Member -type NoteProperty -name RefID -value $refid # Reference ID
                        $objRepValues | Add-Member -type NoteProperty -name StratumType -value $Stratum # StratumType i.e. type 1,2,3 etc
                        $objRepValues | Add-Member -type NoteProperty -name Message -value $timeError # Message from System

                        #Add Objects to our new Array
                        $FinalNtpOutPut += $objRepValues

                    }

                }

               Write-Host "`n***NOTE*** Time Difference (TimeDiff) is calculated against the PDC $PdcOwnerDC" -ForegroundColor White
               Write-Host "`n***NOTE*** Time Difference (TimeDiff) is measured in Seconds" -ForegroundColor White
               Write-Output "`n$CurrentDate --> ***NOTE*** Time Difference (TimeDiff) is calculated against the PDC $PdcOwnerDC" | Add-Content $LogFile
               Write-Output "`n$CurrentDate --> ***NOTE*** Time Difference (TimeDiff) is measured in Seconds" | Add-Content $LogFile
               Write-Output "`n" | Add-Content $LogFile


               $FinalNtpOutPut | Sort-Object DomainController | FT -AutoSize
               $FinalNtpOutPut | Sort-Object DomainController | FT -AutoSize | Out-String | Add-Content $LogFile
               
        }


    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: Monitoring NTP ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Monitoring NTP ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Get RID Pool Information"

if($CheckRidPool)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Display RID information across Forest ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Display RID information across Forest ===================================================================" | Add-Content $LogFile
 
    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $objDomain = New-Object System.DirectoryServices.DirectoryEntry
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {
           
            Write-Host "`nOpening the RID Manager Object...." -ForegroundColor White
            Write-Output "`n$CurrentDate --> Opening the RID Manager Object...." | Add-Content $LogFile
           
            # Open the RID Manager Object
            $strRidManager = [String]::Concat("LDAP://CN=RID Manager$,CN=System,", $objDomain.distinguishedName)
            $objRidManager = New-Object System.DirectoryServices.DirectoryEntry($strRidManager)

            Write-Host "`nChecking FSMO Role Owner...." -ForegroundColor White
            Write-Output "`n$CurrentDate --> Checking FSMO Role Owner...." | Add-Content $LogFile
           
            # Check FSMO Role Owner
            $objRidMaster = New-Object System.DirectoryServices.DirectoryEntry("LDAP://" + $objRidManager.FsmoRoleOwner)
            $objRidMaster = New-Object System.DirectoryServices.DirectoryEntry($objRidMaster.Parent)

            $ridMasterServerName = $objRidMaster.name

            Write-Host "`nThe RID Master has been identified as $ridMasterServerName" -ForegroundColor White
            Write-Output "`n$CurrentDate --> The RID Master has been identified as $ridMasterServerName" | Add-Content $LogFile

            Write-Host "`nCollecting the Available RID Pool...." -ForegroundColor White
            Write-Output "`n$CurrentDate --> Collecting the Available RID Pool...." | Add-Content $LogFile

            # Read Available RID Pool
            $objAvailPool = GetInteger8 $objRidManager.rIDAvailablePool

            # Create array to store RID Data
            $RidDataSet = @()

            # Bind to the Domain Controllers OU
            $objDCOU = New-Object System.DirectoryServices.DirectoryEntry([string]::Concat("LDAP://OU=Domain Controllers,", $objDomain.distinguishedName))

            # Loop through the Domain Controllers OU
            foreach ($objDC in $objDCOU.Children)
            {
                # Bind to the RID Set, note that's it's essential to bind to the domain controller you want data from   
                $objRIDSet = New-Object System.DirectoryServices.DirectoryEntry([string]::Concat("LDAP://", $objDC.dNSHostName, "/", $objDC.rIDSetReferences))
               
                # Add the Data to the array
                try{
                     $RidDataSet += GetRidData $objRIDSet
                 }
                catch [Exception]
                {
                   $objRIDSet = $null
                }
               
            }

            # Display RID Data in a nice table
            Write-Output "`n" | Add-Content $LogFile
            $RidDataSet | FT -AutoSize

            $RidDataSet | FT -AutoSize | Out-String | Add-Content $LogFile

            Write-Output "`n" | Add-Content $LogFile

            Write-Host "`n============================================ Finished: Display RID information across Forest ===================================================================" -ForegroundColor Magenta
            Write-Output "`n============================================ Finished: Display RID information across Forest ===================================================================" | Add-Content $LogFile
 
        }

    }
    catch [Exception]
    {
       
        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

}


#endregion

#region "Draw Active Directory Topology"

if($DrawTopology)
{
     Write-Output "`n" | Add-Content $LogFile
     Write-Output "`n" | Add-Content $LogFile
     Write-Host "`n============================================ Draw Active Directory Topology ===================================================================" -ForegroundColor Magenta
     Write-Output "`n============================================ Draw Active Directory Topology ===================================================================" | Add-Content $LogFile
 

        Add-Type -TypeDefinition @"
        [System.Flags]
            public enum nTDSSiteConnectionSettingsFlags {
            IS_GENERATED                  = 0x00000001,
            TWOWAY_SYNC                   = 0x00000002,
            OVERRIDE_NOTIFY_DEFAULT       = 0x00000004,
            USE_NOTIFY                    = 0x00000008,
            DISABLE_INTERSITE_COMPRESSION = 0x00000010,
            OPT_USER_OWNED_SCHEDULE       = 0x00000020 
        }
"@

        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile

       $RootDSC = [adsi]"LDAP://RootDSE"
       $ConfigNamingContext = $RootDSC.configurationNamingContext

       $ADConnected = $true
   
       Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
       Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

       if($ADConnected)
       {

            try{
               
                Write-Host "`nCollecting Site Information...." -ForegroundColor White
                Write-Output "`n$CurrentDate --> Collecting Site Information...." | Add-Content $LogFile

                # All AD Site Connection Settings
                $SiteConnectionSettings = Search-AD -Filter '(&(objectClass=nTDSConnection))' `
                                                    -Properties * `
                                                    -SearchRoot "LDAP://CN=Sites,$([string]$ConfigNamingContext)"
                $AllSiteConnections = @()

                $ldapregex = [regex]'(?<LDAPType>^.+)\=(?<LDAPName>.+$)'
                Write-Host "`nDrawing Topology Information...." -ForegroundColor White
                Write-Output "`n$CurrentDate --> Drawing Topology Information...." | Add-Content $LogFile
                Foreach ($SiteConnection in $SiteConnectionSettings)
                {
                    If(($SiteConnection.Options.Count -eq 0) -or $SiteSettings.Options -EQ 0)
                    {
                        $SiteConnectionOptions = $null
                    }
                    Else
                    {
                        $SiteConnectionOptions = [Enum]::Parse('nTDSSiteConnectionSettingsFlags', $SiteConnection.Options)
                    }
   
                    $tmp = $SiteConnection.FromServer -split ','
                    if ($tmp[1] -match $ldapregex)
                    {
                        $FromServer = $matches['LDAPName']
                    }
                    else
                    {
                        $FromServer = $SiteConnection.FromServer
                    }
   
                    # Get the server name from the connection DN
                    $tmp = $SiteConnection.distinguishedName -split ','
                    if ($tmp[2] -match $ldapregex)
                    {
                        $Server = $matches['LDAPName']
                    }
                    else
                    {
                        $Server = $SiteConnection.DistinguishedName
                    }

                    $SiteConnProps = @{
                        'DistinguishedName' = $SiteConnection.DistinguishedName
                        'Enabled' = $SiteConnection.EnabledConnection
                        'Options' = $SiteConnectionOptions
                        'FromServer' = $FromServer
                        'Server' = $Server
                    }
                    $AllSiteConnections += New-Object PSObject -Property $SiteConnProps
                }

                #region Generate the graphviz diagram data
                $Output = @'
                digraph test {
                 rankdir = LR
 
'@
            # Add in the dependency information
ForEach ($SiteCon in $AllSiteConnections)
{
    $Output +=
@"   
   
 "$($SiteCon.FromServer)" -> "$($SiteCon.Server)"[label = ""]
"@
}

$Output += @'

}
'@

        Write-Host "`nDrawing of Active Directory Topology is complete. Topology diagram is located in $TopologyPicPath" -ForegroundColor White
        Write-Output "`n$CurrentDate --> Drawing of Active Directory Topology is complete. Topology diagram is located in $TopologyPicPath" | Add-Content $LogFile
        Write-Host "`n***NOTE*** The output is in text format. To draw the actually diagram you will need graphviz’s dot.exe" -ForegroundColor White
        Write-Output "`n$CurrentDate --> ***NOTE*** The output is in text format. To draw the actually diagram you will need graphviz’s dot.exe" | Add-Content $LogFile
        Write-Host "`n***NOTE*** Graphviz’s dot.exe can be downloaded from https://code.google.com/p/graph-viz-portable/downloads/list" -ForegroundColor White
        Write-Output "`n$CurrentDate --> ***NOTE*** Graphviz’s dot.exe can be downloaded from https://code.google.com/p/graph-viz-portable/downloads/list" | Add-Content $LogFile
      
        # Uncomment the following to create a file to later convert into a graph with dot.exe
        IF ((Test-Path $TopologyPicPath)) {Remove-Item $TopologyPicPath} #Remove the Current Diagram
        $Output | Out-File -Encoding ASCII $TopologyPicPath

        # Otherwise feed it into dot.exe and automatically open it up
        #$Output | & 'dot.exe' -Tpng -o services.png
        #ii services.png

        Write-Output "`n" | Add-Content $LogFile

        Write-Host "`n============================================ Finished: Display RID information across Forest ===================================================================" -ForegroundColor Magenta
        Write-Output "`n============================================ Finished: Display RID information across Forest ===================================================================" | Add-Content $LogFile
 

            }
            catch [Exception]
            {
               
                $ADConnected = $false
                Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
                Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
                Exit

            }

       }



}

#endregion

#endregion

#region "Checking DFS-R BackLog Status"

if($CheckDfsr)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Checking DFS-R Backlog ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Checking DFS-R Backlog ===================================================================" | Add-Content $LogFile
 
    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {
           
            $GCs = $forest.FindAllGlobalCatalogs() #Get All Global Catalogue Servers
            Write-Host "`nFound All Global Catalogue Servers" -ForegroundColor Cyan
            $GCs | FT -AutoSize
            Write-Output "`n$CurrentDate --> Found All Global Catalogue Servers" | Add-Content $LogFile
            $GCs | FT -AutoSize | Out-String | Add-Content $LogFile

            $GCNames = @($GCs | Select Name) #Get Global Catalogue Server Names only

            $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name) #Get All Domain Controllers in current Forest
            Write-Host "`nFound All Domain Controllers" -ForegroundColor Cyan
            $ForestDCs | FT -AutoSize
            Write-Output "`n$CurrentDate --> Found All Domain Controllers" | Add-Content $LogFile
            $ForestDCs | FT -AutoSize | Out-String | Add-Content $LogFile
       
            $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name)) #Get All Global Catalogues in current Forest

           
            ForEach($DC in $ForestDCs)
            {
                $DCName = $DC.Name
                $Pingable = PingCheck $DCName
               

                If ($Pingable)
{
                    $NamespaceExists = Check-WMINamespace $DCName "MicrosoftDFS"
                    Write-Host "`n" -ForegroundColor Cyan
                    Write-Output "`n" | Add-Content $LogFile
                    Write-Host "`n" -ForegroundColor Cyan
                    Write-Output "`n" | Add-Content $LogFile
                    If ($NamespaceExists)
                    {
                        Write-Host "`n--------------------------- Server: $DCName ------------------------------------------" -ForegroundColor White
                        Write-Output "`n--------------------------- Server: $DCName ------------------------------------------" | Add-Content $LogFile
                        Write-Host "`n" -ForegroundColor Cyan
                        Write-Output "`n" | Add-Content $LogFile
                        #Write-Debug "Collecting RGroups from $DCName"
                        Write-Host "`nCollecting RGroups from $DCName" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Collecting RGroups from $DCName" | Add-Content $LogFile
                       
                        $RGroups = Get-DFSRGroup $DCName $RGName
                        #Write-Debug "Rgroups = $Rgroups"
                        Write-Host "`nRgroups = $Rgroups" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Rgroups = $Rgroups" | Add-Content $LogFile
                        #Write-Debug "Collecting RFolders from $DCName"
                        Write-Host "`nCollecting RFolders from $DCName" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Collecting RFolders from $DCName" | Add-Content $LogFile
                        $RFolders = Get-DFSRFolder $DCName $RFName
                        #Write-Debug "RFolders = $RFolders"
                        Write-Host "`nRFolders = $RFolders" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> RFolders = $RFolders" | Add-Content $LogFile
                        #Write-Debug "Collecting RConnections from $DCName"
                        Write-Host "`nCollecting RConnections from $DCName" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Collecting RConnections from $DCName" | Add-Content $LogFile
                        $RConnections = Get-DFSRConnections $DCName
                        #Write-Debug "RConnections = $RConnections"
                        Write-Host "`nRConnections = $RConnections" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> RConnections = $RConnections" | Add-Content $LogFile
 
                        #Write-Debug "Calculating Backlog from $DCName"
                        Write-Host "`nCalculating Backlog from $DCName" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Calculating Backlog from $DCName" | Add-Content $LogFile
                        $BacklogInfo = Get-DFSRBacklogInfo $DCName $RGroups $RFolders $RConnections
 
                       
                       
                        $BacklogInfo | sort-object BacklogStatus | FT -AutoSize -GroupBy BacklogStatus
                        $BacklogInfo | sort-object BacklogStatus | FT -AutoSize -GroupBy BacklogStatus | Out-String | Add-Content $LogFile

                        Write-Host "`n--------------------------- End Server: $DCName ------------------------------------------" -ForegroundColor White
                        Write-Output "`n--------------------------- End Server: $DCName ------------------------------------------" | Add-Content $LogFile
                        Write-Host "`n" -ForegroundColor Cyan
                        Write-Output "`n" | Add-Content $LogFile
                     
                      
                                         
                       
                    } else {
                        Write-Error "MicrosoftDFS WMI Namespace does not exist on '$DCName'.  Run locally on a system with the Namespace, or provide computer parameter of that system to run remotely."
                        Write-Output "`n$CurrentDate --> MicrosoftDFS WMI Namespace does not exist on '$DCName'.  Run locally on a system with the Namespace, or provide computer parameter of that system to run remotely." | Add-Content $LogFile
                    }
                } else {
                    Write-Error "The Server '$DCName' did not respond to ping."
                    Write-Output "`n$CurrentDate --> The Server '$DCName' did not respond to ping." | Add-Content $LogFile
                }

            }
                      

            Write-Host "`n============================================ Finished: Checking DFS-R Backlog ===================================================================" -ForegroundColor Magenta
            Write-Output "`n============================================ Finished: Checking DFS-R Backlog ===================================================================" | Add-Content $LogFile
 
        }

    }
    catch [Exception]
    {
       
        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }


}


#endregion

#region "Check for SPNS, UPNS, Duplicate SPNs, and Duplicate UPNs"

if($CheckSPNSandUPNS)
{
    $SupportedOS = $false
    $OSVersionDetails = [System.Environment]::OSVersion.Version
    $Major = $OSVersionDetails.Major.ToString()
    $Minor = $OSVersionDetails.Minor.ToString()
    $OSVersion = $Major + "." + $Minor

    Switch($OSVersion) #Check OS Version. Only Windows Server 2008 R2 and above is supported
    {
        "5.0" {$SupportedOS = $false} #Windows2000
        "5.1" {$SupportedOS = $false} #Windows XP /Windows Server 2003
        "6.0" {$SupportedOS = $false} #Windows Vista /Windows Server 2008
        "6.1" {$SupportedOS = $true} #Windows 7 /Windows Server 2008 R2
        "6.2" {$SupportedOS = $true} #Windows 8 /Windows Server 2012
        "6.3" {$SupportedOS = $true} #Windows 8.1 /Windows Server 2012 R2

    }

    if($SupportedOS)
    {

        if(!(Get-Module ActiveDirectory))
        {
            Import-Module ActiveDirectory #Import the AD Module for this process
        }

        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`n============================================ Checking SPNs and UPNs ===================================================================" -ForegroundColor Magenta
        Write-Output "`n============================================ Checking SPNs and UPNs ===================================================================" | Add-Content $LogFile
   
        try{

            #Connect to AD
            Write-Output "`n" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile
            $ADForestInfo =  Get-ADForest
            Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
            Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
            Write-Host "`nCollecting Active Directory forest information...." -ForegroundColor Yellow
            Write-Output "`n$CurrentDate --> Collecting Active Directory forest information...." | Add-Content $LogFile

            #region "Active irectory Forest Info using Get-ADForest"

            $ADForestApplicationPartitions = $ADForestInfo.ApplicationPartitions
            $ADForestCrossForestReferences = $ADForestInfo.CrossForestReferences
            $ADForestDomainNamingMaster = $ADForestInfo.DomainNamingMaster
            $ADForestDomains = $ADForestInfo.Domains
            $ADForestForestMode = $ADForestInfo.ForestMode
            $ADForestGlobalCatalogs = $ADForestInfo.GlobalCatalogs
            $ADForestName = $ADForestInfo.Name
            $ADForestPartitionsContainer = $ADForestInfo.PartitionsContainer
            $ADForestRootDomain = $ADForestInfo.RootDomain
            $ADForestSchemaMaster = $ADForestInfo.SchemaMaster
            $ADForestSites = $ADForestInfo.Sites
            $ADForestSPNSuffixes = $ADForestInfo.SPNSuffixes
            $ADForestUPNSuffixes = $ADForestInfo.UPNSuffixes

            #endregion
       
            $ADConnected = $true
   
            Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
            Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

            if($ADConnected)
            {
                #region "Get Global Catlogue Information"

                IF ($TargetGC)
                { ## OPEN IF TargetGC has a value
                  $GCInfo = Get-ADDomainController $TargetGC
                  IF ($GCInfo.OperatingSystemVersion -lt 6.0)
                     { ## OPEN IF TargetGC is not running Windows 2008 or higher
                        $LocalSite = (Get-ADDomainController -Discover).Site
                        $NewTargetGC = Get-ADDomainController -Discover -Service 6 -SiteName $LocalSite
                            IF (!$NewTargetGC)
                            { $NewTargetGC = Get-ADDomainController -Discover -Service 6 -NextClosestSite }
                        $LocalGC = $NewTargetGC.HostName + ":3268"
                     } ## CLOSE IF TargetGC is not running Windows 2008 or higher
       
                    ELSE  { $LocalGC = $GCInfo.HostName + ":3268" } 
                } ## CLOSE IF TargetGC has a value
   
            ELSE
                { ## OPEN ELSE TargetGC is not set
                    Write-Host "Discover Local GC running ADWS `r " -ForegroundColor Green
                    Write-Output "$CurrentDate --> Discover Local GC running ADWS `r " | Add-Content $LogFile
                    $LocalSite = (Get-ADDomainController -Discover).Site
                    $NewTargetGC = Get-ADDomainController -Discover -Service 6 -SiteName $LocalSite
                    IF (!$NewTargetGC)
                        { $NewTargetGC = Get-ADDomainController -Discover -Service 6 -NextClosestSite }
                    $tmpServerName = $NewTargetGC.HostName -split "\."
                    $LocalGC = $tmpServerName[0] + ":3268"
                } ## CLOSE ELSE TargetGC is not set

                #endregion

                #region "Check for a UPN"

                IF ($UPNName)
                {  ## OPEN IF UPNName was provided
                ####################################
                # Find Objects with a Specific UPN #
                ####################################

                Write-Host "Identify User Objects configured with the UPN: $UPNName `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Identify User Objects configured with the UPN: $UPNName `r " | Add-Content $LogFile
                try{
                    $Time = (Measure-Command `
                        { [array]$UPNObjectList = Get-ADObject -Server $LocalGC -filter { (ObjectClass -eq "User") -OR (ObjectClass -eq "Computer") } `
                         -property name,distinguishedname,UserPrincipalName | Where { $_.UserPrincipalName -like "$UPNName" }
                        }).Seconds
                    }
                 catch [Exception]
                 {
                   Write-Host "`nUnable to Read UPN Information for $UPNName" -ForegroundColor Red
                   Write-Output "`n$CurrentDate --> Unable to Read UPN Information for $UPNName" | Add-Content $LogFile
    
                 }
                [int]$UPNObjectListCount = $UPNObjectList.Count
                Write-Host "Discovered $UPNObjectListCount User objects configured with the UPN: $UPNName in $Time Seconds `r " -ForegroundColor Green
                Write-Host "The following $UPNObjectListCount user objects are configured with the UPN: `r " -ForegroundColor Green
     
                Write-Output "$CurrentDate --> Discovered $UPNObjectListCount User objects configured with the UPN: $UPNName in $Time Seconds `r " | Add-Content $LogFile
                Write-Output "$CurrentDate --> The following $UPNObjectListCount user objects are configured with the UPN: `r " | Add-Content $LogFile
       
                $UPNObjectList
       
                $UPNObjectList | Out-String | Add-Content $LogFile

                }  ## CLOSE IF UPNName was provided

                #endregion

                #region "Check for a SPN"

                IF ($SPNName)
                {  ## OPEN IF SPNName was provided
                ####################################
                # Find Objects with a Specific SPN #
                ####################################

                Write-Host "Identify User and Computer Objects configured with the Service Principal Name: $SPNName `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Identify User and Computer Objects configured with the Service Principal Name: $SPNName `r " | Add-Content $LogFile
                $Time = (Measure-Command `
                    { [array]$SPNObjectList = Get-ADObject -Server "$LocalGC" -filter { (ObjectClass -eq "User") -OR (ObjectClass -eq "Computer") } `
                     -property name,distinguishedname,ServicePrincipalName | Where { $_.ServicePrincipalName -like "$SPNName" }
                    }).Seconds
                [int]$SPNObjectListCount = $SPNObjectList.Count

                Write-Host "Discovered $SPNObjectListCount User objects configured with the SPN: $SPNName in $Time Seconds `r " -ForegroundColor Green
                Write-Host "The following $SPNObjectListCount user objects are configured with the SPN: `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Discovered $SPNObjectListCount User objects configured with the SPN: $SPNName in $Time Seconds `r " | Add-Content $LogFile
                Write-Output "$CurrentDate --> The following $SPNObjectListCount user objects are configured with the SPN: `r " | Add-Content $LogFile
                $SPNObjectList

                $SPNObjectList | Out-String | Add-Content $LogFile

                }  ## CLOSE IF SPNName was provided

                #endregion
       
                #region "Find Duplicate UPNs"

                IF ($FindDuplicateUPNs)
                {  ## OPEN IF FindDuplicateUPNs = True
                ###########################
                # Discover Duplicate UPNs #
                ###########################
                IF ($AllUPNList) { Clear-Variable AllUPNList ; Clear-Variable DuplicateUPNList }

                Write-Host "Identify User Objects with configured User Principal Names `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Identify User Objects with configured User Principal Names `r " | Add-Content $LogFile
                $Time = (Measure-Command `
                    { $UPNObjectList = Get-ADObject -Server "$LocalGC" -filter { (ObjectClass -eq "User") -OR (ObjectClass -eq "Computer") } `
                     -property name,distinguishedname,UserPrincipalName | Where { $_.UserPrincipalName -ne $NULL }
                    }).Seconds
                $UPNObjectListCount = $UPNObjectList.Count
                Write-Host "Discovered $UPNObjectListCount User with UPNs in $Time Seconds `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Discovered $UPNObjectListCount User with UPNs in $Time Seconds `r " | Add-Content $LogFile

                Write-Host "Building a list of all UPNs....Please Wait!! `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Building a list of all UPNs....Please Wait!! `r " | Add-Content $LogFile
                $Time = (Measure-Command `
                  { ForEach ($UPN in $UPNObjectList)
                    {  ## OPEN ForEach Item in ObjectList
                       ForEach ($Object in $UPN.ServicePrincipalName)
                        {  ## OPEN ForEach Object in Item.ServicePrincipalName
                            [array]$AllUPNList += $Object
                        }  ## CLOSE ForEach Object in Item.ServicePrincipalName
                    }  ## CLOSE ForEach Item in ObjectList
                  }).Seconds   
                Write-Host "UPN List created in $Time Seconds `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> UPN List created in $Time Seconds `r " | Add-Content $LogFile   
       
                    if(!([string]::IsNullOrEmpty($AllUPNList)))
                    {

                        Write-Host "Find duplicates in the UPN list `r " -ForegroundColor Green
                        Write-Output "$CurrentDate --> Find duplicates in the UPN list `r " | Add-Content $LogFile
                        $Time = (Measure-Command `
                          {
                            [array]$AllUPNList = $AllUPNList | sort-object
                            [array]$UniqueUPNs = $AllUPNList | Select -unique
                            [array]$DuplicateUPNs = Compare-Object -ReferenceObject $UniqueUPNs -DifferenceObject $AllUPNList
                          }).Seconds 
                        [int]$UniqueUPNSCount = $UniqueUPNs.Count   
                        ForEach ($DupUPN in $DuplicateUPNs)
                            {  ## OPEN ForEach Dup in DuplicateUPNs
                                [array]$DuplicateUPNList += $DupUPN.InputObject
                            }  ## CLOSE ForEach Dup in DuplicateUPNs
                        [int]$DuplicateUPNsCount = $DuplicateUPNList.Count 
                        Write-Host "Discovered $UniqueUPNsCount Unique UPNs in $Time Seconds `r " -ForegroundColor Green 
                        Write-Output "$CurrentDate --> Discovered $DuplicateUPNsCount Duplicate UPNs in $Time Seconds `r " | Add-Content $LogFile 
                        Write-Host " `r "
                        Write-Output " `r " | Add-Content $LogFile

                        Write-Host "Identifying objects containing the duplicate UPNs... `r " -ForegroundColor Green
                        Write-Output "$CurrentDate --> Identifying objects containing the duplicate UPNs... `r " | Add-Content $LogFile
                        ForEach ($UPN in $DuplicateUPNList)
                            {  ## OPEN ForEach UPN in DuplicateUPNs
                                $DupUPNObjects = $UPNObjectList | Where { $_.ServicePrincipalName -eq $UPN }
                                Write-Host " `r "
                                Write-Host "The UPN $UPN is configured on the following objects:  `r " -ForegroundColor Green
                                Write-Output " `r " | Add-Content $LogFile
                                Write-Output "$CurrentDate --> The UPN $UPN is configured on the following objects:  `r " | Add-Content $LogFile
       
                                ForEach ($Obj in $DupUPNObjects)
                                    {  ## OPEN ForEach Obj in DupUPNObjects
                                      [string]$UPNObjectUPN = $UPN  # $Obj.ServicePrincipalName
                                      $UPNObjectName = $Obj.Name
                                      $UPNObjectClass = $Obj.ObjectClass 
                                      $UPNObjectDN = $Obj.DistinguishedName
             
                                      Write-Host "     *  $UPNObjectName ($UPNObjectClass) has the associated UPN: $UPN [$UPNObjectDN] `r " -ForegroundColor Yellow
                                      Write-Output "$CurrentDate -->     *  $UPNObjectName ($UPNObjectClass) has the associated UPN: $UPN [$UPNObjectDN] `r " | Add-Content $LogFile
             
                                      Write-Host "Creating Inventory Object for $Obj..." -ForegroundColor Yellow
                                      Write-Output "$CurrentDate --> Creating Inventory Object for $Obj..." | Add-Content $LogFile
                                        $InventoryObject = New-Object -TypeName PSObject
                                        $InventoryObject | Add-Member -MemberType NoteProperty -Name UPN -Value ($UPN)
                                        $InventoryObject | Add-Member -MemberType NoteProperty -Name ObjectName -Value $UPNObjectName
                                        $InventoryObject | Add-Member -MemberType NoteProperty -Name UPNObjectClass -Value $UPNObjectClass
                                        $InventoryObject | Add-Member -MemberType NoteProperty -Name ObjectDN -Value $UPNObjectDN
                                        [array]$AllInventory += $InventoryObject
             
                                    }  ## CLOSE ForEach Obj in DupUPNObjects
                            }  ## CLOSE ForEach UPN in DuplicateUPNs

                        # Create Inventory Object
                        [int]$AllInventoryCount = $AllInventory.Count
                        #Write-Output "Exporting File Information ($AllInventoryCount records) to CSV Report file ($CSVReportFile)..."
                        if($AllInventoryCount -gt 0)
                        {
                            $AllInventory | FT -AutoSize
                            $AllInventory | FT -AutoSize | Out-String | Add-Content $LogFile
                            #$AllInventory | Export-CSV $CSVReportFile -NoType
                        }else{

                            Write-Host "Their are no duplicate UPNs`r " -ForegroundColor Green
                            Write-Output "$CurrentDate --> Their are no duplicate UPNs`r " | Add-Content $LogFile

                        }

                    } else{
           
                        Write-Host "Their are no duplicate UPNs`r " -ForegroundColor Green
                        Write-Output "$CurrentDate --> Their are no duplicate UPNs`r " | Add-Content $LogFile
                    }

                } ## CLOSE IF FindDuplicateUPNs = True

                #endregion
       
                #region "Find Duplicate SPNs"

                IF ($FindDuplicateSPNs)
                {  ## OPEN IF FindDuplicateSPNs = True
                ###########################
                # Discover Duplicate SPNs #
                ###########################
                IF ($AllSPNList) { Clear-Variable AllSPNList ; Clear-Variable DuplicateSPNList }

                Write-Host "Identify User and Computer Objects with configured Service Principal Names `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Identify User and Computer Objects with configured Service Principal Names `r " | Add-Content $LogFile 
                $Time = (Measure-Command `
                    { $ObjectList = Get-ADObject -Server "$LocalGC" -filter { (ObjectClass -eq "User") -OR (ObjectClass -eq "Computer") } `
                     -property name,distinguishedname,ServicePrincipalName | Where { $_.ServicePrincipalName -ne $NULL }
                    }).Seconds
                $ObjectListCount = $ObjectList.Count
                Write-Host "Discovered $ObjectListCount User and Computer Objects with SPNs in $Time Seconds `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Discovered $ObjectListCount User and Computer Objects with SPNs in $Time Seconds `r " | Add-Content $LogFile

                Write-Host "Building a list of all SPNs....Please Wait!! `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Building a list of all SPNs....Please Wait!! `r " | Add-Content $LogFile
                $Time = (Measure-Command `
                  { ForEach ($Item in $ObjectList)
                    {  ## OPEN ForEach Item in ObjectList
                       ForEach ($Object in $Item.ServicePrincipalName)
                        {  ## OPEN ForEach Object in Item.ServicePrincipalName
                            [array]$AllSPNList += $Object
                        }  ## CLOSE ForEach Object in Item.ServicePrincipalName
                    }  ## CLOSE ForEach Item in ObjectList
                  }).Seconds   
                Write-Host "SPN List created in $Time Seconds `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> SPN List created in $Time Seconds `r " | Add-Content $LogFile  
 
                Write-Host "Find duplicates in the SPN list `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Find duplicates in the SPN list `r " | Add-Content $LogFile  
                $Time = (Measure-Command `
                  {
                    [array]$AllSPNList = $AllSPNList | sort-object
                    [array]$UniqueSPNs = $AllSPNList | Select -unique
                    [array]$DuplicateSPNs = Compare-Object -ReferenceObject $UniqueSPNs -DifferenceObject $AllSPNList
                  }).Seconds 
                [int]$UniqueSPNSCount = $UniqueSPNS.Count   
                ForEach ($Dup in $DuplicateSPNs)
                    {  ## OPEN ForEach Dup in DuplicateSPNs
                        [array]$DuplicateSPNList += $Dup.InputObject
                    }  ## CLOSE ForEach Dup in DuplicateSPNs
                [int]$DuplicateSPNsCount = $DuplicateSPNList.Count 
                Write-Host "Discovered $UniqueSPNSCount Unique SPNs in $Time Seconds `r " -ForegroundColor Green
                Write-Host "Discovered $DuplicateSPNsCount Duplicate SPNs in $Time Seconds `r " -ForegroundColor Green 
                Write-Host " `r "
                Write-Output "$CurrentDate --> Discovered $UniqueSPNSCount Unique SPNs in $Time Seconds `r " | Add-Content $LogFile 
                Write-Output "$CurrentDate --> Discovered $DuplicateSPNsCount Duplicate SPNs in $Time Seconds `r " | Add-Content $LogFile 
                Write-Output " `r " | Add-Content $LogFile

                Write-Host "Identifying objects containing the duplicate SPNs... `r " -ForegroundColor Green
                Write-Output "$CurrentDate --> Identifying objects containing the duplicate SPNs... `r " | Add-Content $LogFile
                ForEach ($SPN in $DuplicateSPNList)
                    {  ## OPEN ForEach SPN in DuplicateSPNs
                        $DupSPNObjects = $ObjectList | Where { $_.ServicePrincipalName -eq $SPN }
                        Write-Host " `r "
                        Write-Host "The SPN $SPN is configured on the following objects:  `r " -ForegroundColor Green
                        Write-Output " `r "
                        Write-Output "$CurrentDate --> The SPN $SPN is configured on the following objects:  `r " | Add-Content $LogFile
       
                        ForEach ($Obj in $DupSPNObjects)
                            {  ## OPEN ForEach Obj in DupSPNObjects
                              [string]$SPNObjectSPN = $SPN  # $Obj.ServicePrincipalName
                              $SPNObjectName = $Obj.Name
                              $SPNObjectClass = $Obj.ObjectClass 
                              $SPNObjectDN = $Obj.DistinguishedName
             
                              Write-Host "     *  $SPNObjectName ($SPNObjectClass) has the associated SPN: $SPN [$SPNObjectDN] `r " -ForegroundColor Yellow
                              Write-Output "$CurrentDate -->     *  $SPNObjectName ($SPNObjectClass) has the associated SPN: $SPN [$SPNObjectDN] `r " | Add-Content $LogFile
             
                              Write-Host "Creating Inventory Object for $Obj..." -ForegroundColor Yellow
                              Write-Output "$CurrentDate --> Creating Inventory Object for $Obj..." | Add-Content $LogFile
                                $InventoryObject = New-Object -TypeName PSObject
                                $InventoryObject | Add-Member -MemberType NoteProperty -Name SPN -Value ($SPN)
                                $InventoryObject | Add-Member -MemberType NoteProperty -Name ObjectName -Value $SPNObjectName
                                $InventoryObject | Add-Member -MemberType NoteProperty -Name SPNObjectClass -Value $SPNObjectClass
                                $InventoryObject | Add-Member -MemberType NoteProperty -Name ObjectDN -Value $SPNObjectDN
                                [array]$AllInventory += $InventoryObject
             
                            }  ## CLOSE ForEach Obj in DupSPNObjects
                    }  ## CLOSE ForEach SPN in DuplicateSPNs

                # Create Inventory Object
                [int]$AllInventoryCount = $AllInventory.Count
                #Write-Output "Exporting File Information ($AllInventoryCount records) to CSV Report file ($CSVReportFile)..."
                #$AllInventory | Export-CSV $CSVReportFile -NoType
                    if($AllInventoryCount -gt 0)
                    {
                        $AllInventory | FT -AutoSize
                        $AllInventory | FT -AutoSize | Out-String | Add-Content $LogFile
                    }else{

                        Write-Host "Their are no duplicate SPNs`r " -ForegroundColor Green
                        Write-Output "$CurrentDate --> Their are no duplicate SPNs`r " | Add-Content $LogFile
                    }
                }  ## CLOSE IF FindDuplicateSPNs = True


                #endregion
           
                Write-Host "`n============================================ Finished: Checking SPNs and UPNs ===================================================================" -ForegroundColor Magenta
                Write-Output "`n============================================ Finished: Checking SPNs and UPNs ===================================================================" | Add-Content $LogFile
 
            }

       

        }
        catch [Exception]
        {

            $ADConnected = $false
            Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
            Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
            Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
            Exit

        }

    }else{

        Write-Host "`nOperating System not supported for this function." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Operating System not supported for this function." | Add-Content $LogFile
        
    }

}

#endregion

#region "SiteLink and Site Cost Reports"

if($SiteReport)
{
    $ADConnected = $false
    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Site Report ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Site Report ===================================================================" | Add-Content $LogFile
   
    try{

        $NamingContext = (Get-ADRootDSE).ConfigurationNamingContext
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
        $SitesAndSubnets = @()

        if($ADConnected)
        {

            Write-Host "`nCollecting Site Information...." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Collecting Site Information...." | Add-Content $LogFile
           
            Write-Host "`nCollecting Site Cost and additional Information...." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Collecting Site Cost and additional Information...." | Add-Content $LogFile
           
            Write-Host "`nCollecting Site subnet information...." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Collecting Site subnet information...." | Add-Content $LogFile   

            Write-Host "`n"
            Write-Host "`n-------------- Sites ----------------" -ForegroundColor Green
            Write-Output "`n-------------- Sites ----------------" | Add-Content $LogFile 

            Get-ADObject -LDAPFilter '(objectClass=site)' -SearchBase (Get-ADRootDSE).ConfigurationNamingContext -Properties Cost, WhenCreated, Description | Select-Object *, `
                            @{label='IsEmpty';expression={If ($(Get-ADObject -Filter {ObjectClass -eq "nTDSDSA"} -SearchBase $_.DistinguishedName)) {$false} else {$true}}}, `
                            @{label='DCCount';expression={@($(Get-ADObject -Filter {ObjectClass -eq "nTDSDSA"} -SearchBase $_.DistinguishedName)).Count}}, `
                            @{label='SubnetCount';expression={@($(Get-ADObject -Filter {ObjectClass -eq "subnet" -and siteObject -eq $_.DistinguishedName} -SearchBase (Get-ADRootDSE).ConfigurationNamingContext)).Count}}, `
                            @{label='SiteLinkCount';expression={@($(Get-ADObject -Filter {ObjectClass -eq "sitelink" -and siteList -eq $_.DistinguishedName} -SearchBase (Get-ADRootDSE).ConfigurationNamingContext)).Count}} |
                        Sort-Object Name | Format-Table Name, SiteLinkCount, SubnetCount, DCCount, IsEmpty, WhenCreated, Description -AutoSize
          
           
            Get-ADObject -LDAPFilter '(objectClass=site)' -SearchBase (Get-ADRootDSE).ConfigurationNamingContext -Properties Cost, WhenCreated, Description | Select-Object *, `
                            @{label='IsEmpty';expression={If ($(Get-ADObject -Filter {ObjectClass -eq "nTDSDSA"} -SearchBase $_.DistinguishedName)) {$false} else {$true}}}, `
                            @{label='DCCount';expression={@($(Get-ADObject -Filter {ObjectClass -eq "nTDSDSA"} -SearchBase $_.DistinguishedName)).Count}}, `
                            @{label='SubnetCount';expression={@($(Get-ADObject -Filter {ObjectClass -eq "subnet" -and siteObject -eq $_.DistinguishedName} -SearchBase (Get-ADRootDSE).ConfigurationNamingContext)).Count}}, `
                            @{label='SiteLinkCount';expression={@($(Get-ADObject -Filter {ObjectClass -eq "sitelink" -and siteList -eq $_.DistinguishedName} -SearchBase (Get-ADRootDSE).ConfigurationNamingContext)).Count}} |
                        Sort-Object Name | Format-Table Name, SiteLinkCount, SubnetCount, DCCount, IsEmpty, WhenCreated, Description -AutoSize | Out-String | Add-Content $LogFile
           

           Write-Host "`n"

           Write-Host "`n-------------- Sites Costs/Additional Info ----------------" -ForegroundColor Green
           Write-Output "`n-------------- Sites Costs/Additional Info ----------------" | Add-Content $LogFile 

           Get-ADObject -Filter 'objectClass -eq "siteLink"' -Searchbase (Get-ADRootDSE).ConfigurationNamingContext -Property Options, Cost, ReplInterval, SiteList, Schedule | Select-Object Name, @{Name="SiteCount";Expression={$_.SiteList.Count}}, Cost, ReplInterval, @{Name="Schedule";Expression={If($_.Schedule){If(($_.Schedule -Join " ").Contains("240")){"NonDefault"}Else{"24x7"}}Else{"24x7"}}}, Options | Format-Table * -AutoSize

          
           Write-Output "`n"

           Get-ADObject -Filter 'objectClass -eq "siteLink"' -Searchbase (Get-ADRootDSE).ConfigurationNamingContext -Property Options, Cost, ReplInterval, SiteList, Schedule | Select-Object Name, @{Name="SiteCount";Expression={$_.SiteList.Count}}, Cost, ReplInterval, @{Name="Schedule";Expression={If($_.Schedule){If(($_.Schedule -Join " ").Contains("240")){"NonDefault"}Else{"24x7"}}Else{"24x7"}}}, Options | Format-Table * -AutoSize | Out-String | Add-Content $LogFile

           Write-Host "`n-------------- Sites and their Subnets ----------------" -ForegroundColor Green
           Write-Output "`n-------------- Sites and their Subnets ----------------" | Add-Content $LogFile
          
           $siteContainerDN = ("CN=Sites," + $NamingContext)
            $siteObjs = Get-ADObject -SearchBase $siteContainerDN -filter { objectClass -eq "site" } -properties "siteObjectBL", name
            foreach ($siteObj in $siteObjs) {
                $subnetArray = New-Object -Type string[] -ArgumentList $siteObj.siteObjectBL.Count
                $i = 0
                foreach ($subnetDN in $siteObj.siteObjectBL) {
                    $subnetName = $subnetDN.SubString(3, $subnetDN.IndexOf(",CN=Subnets,CN=Sites,") - 3)
                    $subnetArray[$i] = $subnetName
                    $i++
                }
                $siteSubnetObj = New-Object PSCustomObject | Select SiteName, Subnets
                $siteSubnetObj.SiteName = $siteObj.Name
                $siteSubnetObj.Subnets = $subnetArray

                $SitesAndSubnets += $siteSubnetObj
               
               
            }

            $SitesAndSubnets | FT -AutoSize
            $SitesAndSubnets | FT -AutoSize | Out-String | Add-Content $LogFile
            
           Write-Host "`n============================================ Finished: Site Report ===================================================================" -ForegroundColor Magenta
           Write-Output "`n============================================ Finished: Site Report ===================================================================" | Add-Content $LogFile
 

        }


    }
    catch [Exception]
    {
       
        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit
    }

}


#endregion

#region "Get FSMO Roles"

if($FsmoRoles)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ FSMO Role Information ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ FSMO Role Information ===================================================================" | Add-Content $LogFile
   
    $FSMO = @()

    try{

        #Connect to AD
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $forestName = $forest.Name
        $domainName = $forest.Domains | Out-String
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
        $ADConnected = $true
   
        Write-Host "`nConnection to Active Directory is successful...." -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> Connection to Active Directory is successful...." | Add-Content $LogFile

        if($ADConnected)
        {

                Write-Host "`nCollecting FSMO Role Owners..." -ForeGroundColor Green
                Write-Host "`nCurrent Forest: $forestName" -ForeGroundColor Cyan
                Write-Output "`n$CurrentDate --> Collecting FSMO Role Owners..." | Add-Content $LogFile
                Write-Output "`n$CurrentDate --> Current Forest: $forestName" | Add-Content $LogFile
                Write-Host ""

                $PdcRoleOwner = $forest.Domains.PdcRoleOwner.Name -split "\."
                $RidRoleOwner = $forest.Domains.RidRoleOwner.Name -split "\."
                $InfraRoleOwner = $forest.Domains.InfrastructureRoleOwner.Name -split "\."
                $DomainMasterRoleOwner = $forest.NamingRoleOwner -split "\."
                $SchemaMasterRoleOwner = $forest.SchemaRoleOwner -split "\."

                $objRepValues = New-Object System.Object
                $objRepValues | Add-Member -type NoteProperty -name PDC -value $PdcRoleOwner[0] # PDC Emulator
                $objRepValues | Add-Member -type NoteProperty -name RID  -value $RidRoleOwner[0] # RID Master
                $objRepValues | Add-Member -type NoteProperty -name Infrastructure  -value $InfraRoleOwner[0] # Infrastructure Master
                $objRepValues | Add-Member -type NoteProperty -name Domain  -value $DomainMasterRoleOwner[0] # Domain Master
                $objRepValues | Add-Member -type NoteProperty -name Schema -value $SchemaMasterRoleOwner[0] # Schema Master
               
                $FSMO += $objRepValues
                Write-Host "`n"
                Write-Host "`n------------------- Current FSMO Role Owners ------------------------" -ForegroundColor Cyan
                Write-Output "`n" | Add-Content $LogFile
                Write-Output "`n------------------- Current FSMO Role Owners ------------------------" | Add-Content $LogFile

                $FSMO | FT -AutoSize
                $FSMO | FT -AutoSize | Out-String | Add-Content $LogFile


        }
    }
    catch [Exception]
    {
       
        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory Global Catalogue Servers....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Global Catalogue Servers....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

    Write-Host "`n============================================ Finished: FSMO Role Information ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: FSMO Role Information ===================================================================" | Add-Content $LogFile
  

}

#endregion

#region "Generate Kerberos Toke Size Report"

#region "ReadMe First"
<#
I was looking for a way to further troubleshoot and improve Active Directory
One of the key aspects of Active Directory is Kerberos Authentication. For a deeper insight into Kerberos refer to: http://technet.microsoft.com/en-us/library/bb742516.aspx
#Really Great Script to include refer to: http://www.jhouseconsulting.com/2013/12/20/script-to-create-a-kerberos-token-size-report-1041

#>
#endregion

if($KerberosTokenSizeReport)
{

    Write-Output "`n" | Add-Content $LogFile
    Write-Output "`n" | Add-Content $LogFile
    Write-Host "`n============================================ Kerberos Token Size Report ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Kerberos Token Size Report ===================================================================" | Add-Content $LogFile
   
    if(!(Test-DotNetFrameWork35)) #Test for DotNet 3.5 before proceeding
    {
       
        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nDotNet 3.5 is required. Please install before proceeding any further...Exiting Script." -ForegroundColor Yellow
        Write-Output "`n$CurrentDate --> DotNet 3.5 is required. Please install before proceeding any further...Exiting Script." | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit
  
    }else{

        Write-Output "`n" | Add-Content $LogFile
        Write-Output "`n" | Add-Content $LogFile
        Write-Host "`nDotNet 3.5 is Installed...Proceeding with Script." -ForegroundColor Green
        Write-Output "`n$CurrentDate --> DotNet 3.5 is Installed...Proceeding with Script." | Add-Content $LogFile
    
    }
   
    try{
        IF ((Test-Path $TokenReportPath)) {Remove-Item $TokenReportPath} #Remove the CSV report before generating a new one.

        $array = @()
        $TotalUsersProcessed = 0
        $UserCount = 0
        $GroupCount = 0
        $LargestTokenSize = 0
        $TotalGoodTokens = 0
        $TotalTokensBetween8and12K = 0
        $TotalLargeTokens = 0
        $TotalVeryLargeTokens = 0

        $ADRoot = ([System.DirectoryServices.DirectoryEntry]"LDAP://RootDSE")
        $DefaultNamingContext = $ADRoot.defaultNamingContext
 
        # Derive FQDN Domain Name
        $TempDefaultNamingContext = $DefaultNamingContext.ToString().ToUpper()
        $DomainName = $TempDefaultNamingContext.Replace(",DC=",".")
        $DomainName = $DomainName.Replace("DC=","")
 
        # Create an LDAP search for all enabled users not marked as criticalsystemobjects to avoid system accounts
        $ADFilter = "(&(objectClass=user)(objectcategory=person)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!(isCriticalSystemObject=TRUE))(!name=IUSR*)(!name=IWAM*)(!name=ASPNET))"
        $ADPropertyList = @("distinguishedname","samAccountName","userAccountControl","objectsid","sidhistory","primaryGroupID","primarygrouptoken","lastlogontimestamp","memberof")
        $ADScope = "SUBTREE"
        $ADPageSize = 1000
        $ADSearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$($DefaultNamingContext)")
        $ADSearcher = New-Object System.DirectoryServices.DirectorySearcher
        $ADSearcher.SearchRoot = $ADSearchRoot
        $ADSearcher.PageSize = $ADPageSize
        $ADSearcher.Filter = $ADFilter
        $ADSearcher.SearchScope = $ADScope
        if ($ADPropertyList) {
          foreach ($ADProperty in $ADPropertyList) {
            [Void]$ADSearcher.PropertiesToLoad.Add($ADProperty)
          }
        }
        Write-Host "`nCollecting all User, group, information...Please wait!!!" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Collecting all User, group, information...Please wait!!!" | Add-Content $LogFile
        $Users = $ADSearcher.Findall()
        $UserCount = $users.Count
        Write-Host "`nThere are $UserCount Active Directory User/Group Objects" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> There are $UserCount Active Directory User/Group Objects" | Add-Content $LogFile
      
        Write-Host "`nCalculating Token Size against all User/Group objects...Please wait!!!" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Calculating Token Size against all User/Group objects...Please wait!!!" | Add-Content $LogFile
        Write-Host "`n"
        Write-Output "`n" | Add-Content $LogFile

        if ($UserCount -ne 0) {
          foreach($user in $users) {
            #$user.Properties
            #$user.Properties.propertynames
            $lastLogonTimeStamp = ""
            $lastLogon = ""
            $UserDN = $user.Properties.distinguishedname[0]
            $samAccountName = $user.Properties.samaccountname[0]
            If (($user.Properties.lastlogontimestamp | Measure-Object).Count -gt 0) {
              $lastLogonTimeStamp = $user.Properties.lastlogontimestamp[0]
              $lastLogon = [System.DateTime]::FromFileTime($lastLogonTimeStamp)
              if ($lastLogon -match "1/01/1601") {$lastLogon = "Never logged on before"}
            } else {
              $lastLogon = "Never logged on before"
            }
            $OU = $user.GetDirectoryEntry().Parent
            $OU = $OU -replace ("LDAP:\/\/","")

            try{

                # Get user SID
                $arruserSID = New-Object System.Security.Principal.SecurityIdentifier($user.Properties.objectsid[0], 0)
                $userSID = $arruserSID.Value

                # Get the SID of the Domain the account is in
                $AccountDomainSid = $arruserSID.AccountDomainSid.Value

                # Get User Account Control & Primary Group by binding to the user account
                $objUser = [ADSI]("LDAP://" + $UserDN)
                $UACValue = $objUser.useraccountcontrol[0]
                $primarygroupID = $objUser.PrimaryGroupID
                # Primary group can be calculated by merging the account domain SID and primary group ID
                $primarygroupSID = $AccountDomainSid + "-" + $primarygroupID.ToString()
                $primarygroup = [adsi]("LDAP://<SID=$primarygroupSID>")
                $primarygroupname = $primarygroup.name
                $objUser = $null

                # Get SID history
                $SIDCounter = 0
                if ($user.Properties.sidhistory -ne $null) {
                  foreach ($sidhistory in $user.Properties.sidhistory) {
                    $SIDHistObj = New-Object System.Security.Principal.SecurityIdentifier($sidhistory, 0)
                    #Write-Host -ForegroundColor green $SIDHistObj.Value "is in the SIDHistory."
                    $SIDCounter++
                  }
                }
                $SIDHistObj = $null

            }
            catch [Exception]
            {
               
                Write-Host "`nUnable to enumerate SID Information: $($_.Exception.Message)....Exiting Script" -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Unable to enumerate SID Information: $($_.Exception.Message)....Exiting Script" | Add-Content $LogFile
     
            }

            $TotalUsersProcessed ++
           
            # Use TokenGroups Attribute
            If ($UseTokenGroups) {
              $UserAccount = [ADSI]"$($User.Path)"
              $UserAccount.GetInfoEx(@("tokenGroups"),0) | Out-Null
              $ErrorActionPreference = "continue"
              $error.Clear()
              $groups = $UserAccount.GetEx("tokengroups")
              if ($Error) {
                Write-Warning "  Tokengroups not readable"
                $Groups=@()   #empty enumeration
              }
              $GroupCount = 0
              # Note that the tokengroups includes all principals, which includes siDHistory, so we need
              # to subtract the sIDHistory count to correctly report on the number of groups in the token.
              $GroupCount = $groups.count - $SIDCounter

              $SecurityDomainLocalScope = 0
              $SecurityGlobalInternalScope = 0
              $SecurityGlobalExternalScope = 0
              $SecurityUniversalInternalScope = 0
              $SecurityUniversalExternalScope = 0

              foreach($token in $groups) {
                $principal = New-Object System.Security.Principal.SecurityIdentifier($token,0)
                $GroupSid = $principal.value
                #$group = $principal.Translate([System.Security.Principal.NTAccount])
                #$group.value
                $grp = [ADSI]"LDAP://<SID=$GroupSid>"
                if ($grp.Path -ne $null) {
                  $grpdn = $grp.distinguishedName.tostring().ToLower()
                  $grouptype = $grp.groupType.psbase.value

                  switch -exact ($GroupType) {
                    "-2147483646"   {
                                    # Global security scope
                                    if ($GroupSid -match $DomainSID)
                                    {
                                      $SecurityGlobalInternalScope++
                                    } else {
                                      # Global groups from others.
                                      $SecurityGlobalExternalScope++
                                    }
                                    }
                    "-2147483644"   {
                                    # Domain Local scope
                                    $SecurityDomainLocalScope++
                                    }
                    "-2147483643"   {
                                    # Domain Local BuildIn scope
                                    $SecurityDomainLocalScope++
                                    }
                    "-2147483640"   {
                                    # Universal security scope
                                    if ($GroupSid -match $AccountDomainSid)
                                    {
                                      $SecurityUniversalInternalScope++
                                    } else {
                                      # Universal groups from others.
                                      $SecurityUniversalExternalScope++
                                    }
                                    }
                  }
                }
              }
            }

            # Use GetAuthorizationGroups() Method
            If ($UseGetAuthorizationGroups) {

              $userPrincipal = Get-UserPrincipal -userName $SamAccountName -cName $DomainName -cContainer "$OU"

              $GroupCount = 0
              $SecurityDomainLocalScope = 0
              $SecurityGlobalInternalScope = 0
              $SecurityGlobalExternalScope = 0
              $SecurityUniversalInternalScope = 0
              $SecurityUniversalExternalScope = 0

              # Use GetAuthorizationGroups() for Indirect Group MemberShip, which includes all Nested groups and the Primary group
              Try {
                $groups = $userPrincipal.GetAuthorizationGroups() | select SamAccountName, GroupScope, SID
       
                $GroupCount = $groups.count

                foreach ($group in $groups) {
                  $GroupSid = $group.SID.value
                  #$group

                  switch ($group.GroupScope)
                    {
                      "Local" {
                        # Domain Local & Domain Local BuildIn scope
                        $SecurityDomainLocalScope++
                        }
                      "Global" {
                        # Global security scope
                        if ($GroupSid -match $DomainSID) {
                          $SecurityGlobalInternalScope++
                        } else {
                          # Global groups from others.
                          $SecurityGlobalExternalScope++
                        }
                      }
                        "Universal" {
                        # Universal security scope
                        if ($GroupSid -match $AccountDomainSid) {
                          $SecurityUniversalInternalScope++
                        } else {
                          # Universal groups from others.
                          $SecurityUniversalExternalScope++
                        }
                      }
                    }
                }
              }
              Catch {
                write-host "Error with the GetAuthorizationGroups() method: $($_.Exception.Message)" -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Error with the GetAuthorizationGroups() method: $($_.Exception.Message)" | Add-Content $LogFile
              }
            }

            If ($DisplayOutputOnScreen) {
              Write-Host -ForegroundColor green "`n---------------- Current SamAccount $SamAccountName -------------------"
              Write-Host -ForegroundColor green "Checking the token of user $SamAccountName in domain $DomainName"
              Write-Host -ForegroundColor green "There are $GroupCount groups in the token."
              Write-Host -ForegroundColor green "- $SecurityDomainLocalScope are domain local security groups."
              Write-Host -ForegroundColor green "- $SecurityGlobalInternalScope are domain global scope security groups inside the users domain."
              Write-Host -ForegroundColor green "- $SecurityGlobalExternalScope are domain global scope security groups outside the users domain."
              Write-Host -ForegroundColor green "- $SecurityUniversalInternalScope are universal security groups inside the users domain."
              Write-Host -ForegroundColor green "- $SecurityUniversalExternalScope are universal security groups outside the users domain."
              Write-host -ForegroundColor green "The primary group is $primarygroupname."
              Write-host -ForegroundColor green "There are $SIDCounter SIDs in the users SIDHistory."
              Write-Host -ForegroundColor green "The current userAccountControl value is $UACValue."
              Write-Host "`n-----------------------------------------------------------------------------------------------"
              Write-Host "`n"
            }

            Write-Output "`n---------------- Current SamAccount $SamAccountName -------------------" | Add-Content $LogFile
            Write-Output "$CurrentDate --> Checking the token of user $SamAccountName in domain $DomainName" | Add-Content $LogFile
            Write-Output "$CurrentDate --> There are $GroupCount groups in the token." | Add-Content $LogFile
            Write-Output "$CurrentDate --> - $SecurityDomainLocalScope are domain local security groups." | Add-Content $LogFile
            Write-Output "$CurrentDate --> - $SecurityGlobalInternalScope are domain global scope security groups inside the users domain." | Add-Content $LogFile
            Write-Output "$CurrentDate --> - $SecurityGlobalExternalScope are domain global scope security groups outside the users domain." | Add-Content $LogFile
            Write-Output "$CurrentDate --> - $SecurityUniversalInternalScope are universal security groups inside the users domain." | Add-Content $LogFile
            Write-Output "$CurrentDate --> - $SecurityUniversalExternalScope are universal security groups outside the users domain." | Add-Content $LogFile
            Write-Output "$CurrentDate --> The primary group is $primarygroupname." | Add-Content $LogFile
            Write-Output "$CurrentDate --> There are $SIDCounter SIDs in the users SIDHistory." | Add-Content $LogFile
            Write-Output "$CurrentDate --> The current userAccountControl value is $UACValue." | Add-Content $LogFile
            Write-Output "`n------------------------------------------------------------------------" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile

            $TrustedforDelegation = $false
            if ((($UACValue -bor 0x80000) -eq $UACValue) -OR (($UACValue -bor 0x1000000) -eq $UACValue)) {
              $TrustedforDelegation = $true
            }

            # Calculate the current token size, taking into account whether or not the account is trusted for delegation or not.
            $TokenSize = 1200 + (40 * ($SecurityDomainLocalScope + $SecurityGlobalExternalScope + $SecurityUniversalExternalScope + $SIDCounter)) + (8 * ($SecurityGlobalInternalScope  + $SecurityUniversalInternalScope))
            if ($TrustedforDelegation -eq $false) {
              If ($DisplayOutputOnScreen) {
                Write-Host -ForegroundColor green "Token size is $Tokensize and the user is not trusted for delegation."
                Write-Output "$CurrentDate --> Token size is $Tokensize and the user is not trusted for delegation." | Add-Content $LogFile
              }
            } else {
              $TokenSize = 2 * $TokenSize
              If ($DisplayOutputOnScreen) {
                Write-Host -ForegroundColor green "Token size is $Tokensize and the user is trusted for delegation."
                Write-Output "$CurrentDate --> Token size is $Tokensize and the user is trusted for delegation." | Add-Content $LogFile
              }
            }

            If ($TokenSize -le 12000) {
              $TotalGoodTokens ++
              If ($TokenSize -gt 8192) {
                $TotalTokensBetween8and12K ++
              }
            } elseIf ($TokenSize -le 48000) {
              $TotalLargeTokens ++
            } else {
              $TotalVeryLargeTokens ++
            }

            If ($TokenSize -gt $LargestTokenSize) {
              $LargestTokenSize = $TokenSize
              $LargestTokenUser = $SamAccountName
            }

            If ($TokenSize -ge $TokensSizeThreshold) {
              $obj = New-Object -TypeName PSObject
              $obj | Add-Member -MemberType NoteProperty -Name "Domain" -value $DomainName
              $obj | Add-Member -MemberType NoteProperty -Name "SamAccountName" -value $SamAccountName
              $obj | Add-Member -MemberType NoteProperty -Name "TokenSize" -value $TokenSize
              $obj | Add-Member -MemberType NoteProperty -Name "Memberships" -value $GroupCount
              $obj | Add-Member -MemberType NoteProperty -Name "DomainLocal" -value $SecurityDomainLocalScope
              $obj | Add-Member -MemberType NoteProperty -Name "GlobalInternal" -value $SecurityGlobalInternalScope
              $obj | Add-Member -MemberType NoteProperty -Name "GlobalExternal" -value $SecurityGlobalExternalScope
              $obj | Add-Member -MemberType NoteProperty -Name "UniversalInternal" -value $SecurityUniversalInternalScope
              $obj | Add-Member -MemberType NoteProperty -Name "UniversalExternal" -value $SecurityUniversalExternalScope
              $obj | Add-Member -MemberType NoteProperty -Name "SIDHistory" -value $SIDCounter
              $obj | Add-Member -MemberType NoteProperty -Name "UACValue" -value $UACValue
              $obj | Add-Member -MemberType NoteProperty -Name "TrustedforDelegation" -value $TrustedforDelegation
              $obj | Add-Member -MemberType NoteProperty -Name "LastLogon" -value $lastLogon
              $array += $obj
            }

           
          }


            Write-Host "`n"           
            Write-Host -ForegroundColor green "`n-------------------------- Summary ------------------------------------"
            Write-Host "`n"
            Write-Host -ForegroundColor green "- Processed $UserCount user accounts."
            Write-Host -ForegroundColor green "- $TotalGoodTokens have a calculated token size of less than or equal to 12000 bytes."
            Write-Host "`n-----------------------------------------------------------------------------------------------"
            Write-Host "`n"

            Write-Output "`n" | Add-Content $LogFile
            Write-Output "`n-------------------------- Summary ------------------------------------" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile
            Write-Output "$CurrentDate --> - Processed $UserCount user accounts." | Add-Content $LogFile
            Write-Output "$CurrentDate --> - $TotalGoodTokens have a calculated token size of less than or equal to 12000 bytes." | Add-Content $LogFile
            Write-Output "`n------------------------------------------------------------------------" | Add-Content $LogFile
            Write-Output "`n" | Add-Content $LogFile
          
            If ($TotalGoodTokens -gt 0) {
              Write-Host -ForegroundColor green "  - These users are good."
              Write-Output "$CurrentDate --> All Good - These users are good." | Add-Content $LogFile
            }
            If ($TotalTokensBetween8and12K -gt 0) {
              Write-Host -ForegroundColor Yellow "  - Although $TotalTokensBetween8and12K of these user accounts have tokens above 8K and should therefore be reviewed."
              Write-Output "$CurrentDate --> Warning - Although $TotalTokensBetween8and12K of these user accounts have tokens above 8K and should therefore be reviewed." | Add-Content $LogFile
            }
            Write-Host -ForegroundColor Yellow "- $TotalLargeTokens have a calculated token size larger than 12000 bytes."
            Write-Output "$CurrentDate --> - $TotalLargeTokens have a calculated token size larger than 12000 bytes." | Add-Content $LogFile
            If ($TotalLargeTokens -gt 0) {
              Write-Host -ForegroundColor Yellow "  - These users will be okay if you have increased the MaxTokenSize to 48000 bytes.`n  - Consider reducing direct and transitive (nested) group memberships."
              Write-Output "$CurrentDate --> Warning - These users will be okay if you have increased the MaxTokenSize to 48000 bytes.`n  - Consider reducing direct and transitive (nested) group memberships." | Add-Content $LogFile
            }
            Write-Host -ForegroundColor red "- $TotalVeryLargeTokens have a calculated token size larger than 48000 bytes."
            Write-Output "$CurrentDate --> Critical - $TotalVeryLargeTokens have a calculated token size larger than 48000 bytes." | Add-Content $LogFile
            If ($TotalVeryLargeTokens -gt 0) {
              Write-Host -ForegroundColor red "  - These users will have problems. Do NOT increase the MaxTokenSize beyond 48000 bytes.`n  - Reduce the direct and transitive (nested) group memberships."
              Write-Output "$CurrentDate --> Critical - These users will have problems. Do NOT increase the MaxTokenSize beyond 48000 bytes.`n  - Reduce the direct and transitive (nested) group memberships." | Add-Content $LogFile
            }
            Write-Host -ForegroundColor green "- $LargestTokenUser has the largest calculated token size of $LargestTokenSize bytes in the $DomainName domain."
            Write-Output "$CurrentDate --> - $LargestTokenUser has the largest calculated token size of $LargestTokenSize bytes in the $DomainName domain." | Add-Content $LogFile
         

          # Write-Output $array | Format-Table

          $array | Sort-Object TokenSize -descending | select-object -first $TopUsers | FT -AutoSize
          $array | Sort-Object TokenSize -descending | select-object -first $TopUsers | FT -AutoSize | Out-String | Add-Content $LogFile
          $array | Sort-Object TokenSize -descending | select-object -first $TopUsers | export-csv -notype -path "$TokenReportPath" -Delimiter ';'
         

          # Remove the quotes
          (get-content "$TokenReportPath") |% {$_ -replace '"',""} | out-file "$TokenReportPath" -Fo -En ascii
        }



    }
    catch [Exception]
    {

        $ADConnected = $false
        Write-Host "`nUnable to enumerate Active Directory: $($_.Exception.Message)....Exiting Script" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory: $($_.Exception.Message)....Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit
    }

    Write-Host "`n============================================ Finished: Kerberos Token Size Report ===================================================================" -ForegroundColor Magenta
    Write-Output "`n============================================ Finished: Kerberos Token Size Report ===================================================================" | Add-Content $LogFile
  
}

#endregion

Write-Output "`n" | Add-Content $LogFile
Write-Output "`n********************************************************************** Logging Finished *******************************************************************************************************************" | Add-Content $LogFile
Write-Output "`n" | Add-Content $LogFile


Enjoy. As always please leave your comments related to this article.


Replicate-AD.ps1 (244.8KB)

Powershell: Audit DHCP Servers

Hi Guys,

Here is another cool new script, which can be used to audit your DHCP Servers.

<#

Collect DHCP Server information from Authorised DHCP Servers
Written by Michael Aksoy


#>

#region "Functions"


Function Search-AD
{
    param (
        [string[]]$Filter,
        [string[]]$Properties = @('Name','ADSPath'),
        [string]$SearchRoot,
        [switch]$DontJoinAttributeValues
    )
    if ($SearchRoot)
    {
        $Root = [ADSI]$SearchRoot
    }
    else
    {
        $Root = [ADSI]''
    }
    if ($Filter)
    {
        $LDAP = "(&({0}))" -f ($Filter -join ')(')
    }
    else
    {
        $LDAP = "(name=*)"
    }
    try
    {
        (New-Object ADSISearcher -ArgumentList @(
            $Root,
            $LDAP,
            $Properties
        ) -Property @{
            PageSize = 1000
        }).FindAll() | ForEach-Object {
            $ObjectProps = @{}
            $_.Properties.GetEnumerator() |
                Foreach-Object {
                    $Val = @($_.Value)
                    if ($_.Name -ne $null)
                    {
                        if ($DontJoinAttributeValues -and ($Val.Count -gt 1))
                        {
                            $ObjectProps.Add(
                                $_.Name,
                                ($_.Value)
                            )
                        }
                        else
                        {
                            $ObjectProps.Add(
                                $_.Name,
                                (-join $_.Value)
                            )
                        }
                    }
                }
            if ($ObjectProps.psbase.keys.count -ge 1)
            {
                New-Object PSObject -Property $ObjectProps |
                    select $Properties
            }
        }
    }
    catch
    {
        Write-Warning -Message ('Search-AD: Filter - {0}: Root - {1}: Error - {2}' -f $LDAP,$Root.Path,$_.Exception.Message)
    }
}

#endregion

#region "Variables"
   
    try{
        #$myCreds = Get-Credential
        $ADConnected = $true
        $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
        $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $GCs = $forest.FindAllGlobalCatalogs()
        $GCNames = @($GCs | Select Name)
        $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name)
        $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name))
        $schemapartition = $schema.Name
        $RootDSC = [adsi]"LDAP://RootDSE"
        $DomNamingContext = $RootDSC.RootDomainNamingContext
        $ConfigNamingContext = $RootDSC.configurationNamingContext
       
        $DomainDNSZones = @()
        $ExcelExists = $false
    }
    catch
    {
        $ADConnected = $false
    }

#endregion

#region "Collect DHCP Server Information"

if($ADConnected)
{
    Write-Host "Connected to Active Directory Successfully" -ForegroundColor DarkGreen
   
    #region "Get DHCP Servers from AD"
   
    Write-Host "Collecting DHCP Servers from Active Directory...... Please wait!!" -ForegroundColor DarkGreen
   
    $DHCPServers = @(Search-AD -Filter '(objectclass=dHCPClass)' `
                                           -Properties Name,WhenCreated `
                                           -SearchRoot "LDAP://$([string]$ConfigNamingContext)" |
                                 Where {$_.Name -ne 'DhcpRoot'})
                                 
    #endregion
   
    foreach($DHCPServer in $DHCPServers.Name)
    {
        Write-Host "Enumerating DHCP Server $DHCPServer" -ForegroundColor DarkGreen
       
        #region "Get DHCP Server Data using netsh"
       
        $mibInfo = netsh dhcp server \\$DHCPServer show mibinfo

        $discover = $mibInfo | Where-Object {$_-match "Discovers ="} | ForEach-Object{$_-replace "Discovers =",""}
        $offer = $mibInfo | Where-Object {$_-cmatch "Offers ="} | ForEach-Object{$_-replace "Offers =",""} | ForEach-Object{$_-replace "Delayed ",""}
        $dOffer = $mibInfo | Where-Object {$_-match "Delayed Offers ="} | ForEach-Object{$_-replace "Delayed Offers =",""}
        $requests = $mibInfo | Where-Object {$_-match "Requests ="} | ForEach-Object{$_-replace "Requests =",""}
        $acks = $mibInfo | Where-Object {$_-match "Acks ="} | ForEach-Object{$_-replace "Acks =",""}
        $naks = $mibInfo | Where-Object {$_-match "Naks ="} | ForEach-Object{$_-replace "Naks =",""}
        $declines = $mibInfo | Where-Object {$_-match "Declines ="} | ForEach-Object{$_-replace "Declines =",""}
        $releases = $mibInfo | Where-Object {$_-match "Releases ="} | ForEach-Object{$_-replace "Releases =",""}
        $scopes = $mibInfo | Where-Object {$_-match "Scopes ="} | ForEach-Object{$_-replace "Scopes =",""}
        $scopesdelay = $mibInfo | Where-Object {$_-match "Scopes with Delay configured="} | ForEach-Object{$_-replace "Scopes with Delay configured=",""}
        $subNet = $mibInfo | Where-Object {$_-match "Subnet ="} | ForEach-Object{$_-replace "Subnet =",""}
       
        #endregion
       
        try{
            $offer2 = $offer[0]
       
        }
        catch{
            $offer2 = $offer
        }

        $dhcpDataProps = @{
                DHCPServerName = $DHCPServer
                DHCPDiscovers = $discover
                DHCPOffers = $offer2
                DHCPDelayedOffer = $dOffer
                DHCPRequests = $requests
                DHCPAcks = $acks
                DHCPNaks = $naks
                DHCPDeclines = $declines
                DHCPReleases = $releases
                DHCPScopes = $scopes
                DHCPScopeDelays = $scopesdelay
                DHCPScopeSubnets = $subNet
            }
           
            $DHCPServerData = New-Object psobject -Property $dhcpDataProps
           
            #create a Excel Document to start documenting the captured results
           
            try{
                if($ExcelExists -eq $false)
                {
                    #Create an Exxcel Object
                    Write-Host "Creating Excel Object" -ForegroundColor DarkGreen
                    $Excel = New-Object -ComObject Excel.Application -ErrorAction Stop
                    $ExcelExists = $True
                    $Excel.visible = $True
                    #Start-Sleep -s 1
                    $Workbook = $Excel.Workbooks.Add()
                    $Excel.DisplayAlerts = $false
                   
                    $intRow = 2
                    $intCol = 1
                    $BadColor = 13551615    #Light Red
                    $BadText = -16383844    #Dark Red
                    $GoodColor = 13561798    #Light Green
                    $GoodText = -16752384    #Dark Green
                    $Worksheet = $Workbook.Sheets.Add()
                   
                    $Worksheet.Name = "DHCPServers"
                    $Range = $Worksheet.Range("a1","k1")
                   
                    # Header
                   $range = $Workbook.ActiveSheet.Range("a1","k1")
                   $range.Interior.ColorIndex = 19
                   $range.Font.ColorIndex = 11
                   $range.Font.Bold = $True
                   $range.HorizontalAlignment = -4108
                  
                   $Worksheet.Cells.Item(1,2).FormulaLocal = "DHCP Discovers"
                   $Worksheet.Cells.Item(1,3).FormulaLocal = "DHCP Offers"
                   $Worksheet.Cells.Item(1,4).FormulaLocal = "DHCP Delayed Offers"
                   $Worksheet.Cells.Item(1,5).FormulaLocal = "DHCP Acks"
                   $Worksheet.Cells.Item(1,6).FormulaLocal = "DHCP Naks"
                   $Worksheet.Cells.Item(1,7).FormulaLocal = "DHCP Declines"
                   $Worksheet.Cells.Item(1,8).FormulaLocal = "DHCP Releases"
                   $Worksheet.Cells.Item(1,9).FormulaLocal = "DHCP Scopes"
                   $Worksheet.Cells.Item(1,10).FormulaLocal = "DHCP Scope Delay"
                   $Worksheet.Cells.Item(1,11).FormulaLocal = "DHCP Scope Subnets"
                  
                   Write-Host "Populating Excel with DHCP Server $DHCPServer Data...." -ForegroundColor DarkGreen
                  
                   $Worksheet.Cells.Item($intRow,$intCol).FormulaLocal = $DHCPServerData.DHCPServerName
                   $Worksheet.Cells.Item($intRow,$intCol + 1).FormulaLocal = $DHCPServerData.DHCPDiscovers
                   $Worksheet.Cells.Item($intRow,$intCol + 2).FormulaLocal = $DHCPServerData.DHCPOffers
                   $Worksheet.Cells.Item($intRow,$intCol + 3).FormulaLocal = $DHCPServerData.DHCPDelayedOffer
                   $Worksheet.Cells.Item($intRow,$intCol + 4).FormulaLocal = $DHCPServerData.DHCPAcks
                   $Worksheet.Cells.Item($intRow,$intCol + 5).FormulaLocal = $DHCPServerData.DHCPNaks
                   $Worksheet.Cells.Item($intRow,$intCol + 6).FormulaLocal = $DHCPServerData.DHCPDeclines
                   $Worksheet.Cells.Item($intRow,$intCol + 7).FormulaLocal = $DHCPServerData.DHCPReleases
                   $Worksheet.Cells.Item($intRow,$intCol + 8).FormulaLocal = $DHCPServerData.DHCPScopes
                   $Worksheet.Cells.Item($intRow,$intCol + 9).FormulaLocal = $DHCPServerData.DHCPScopeDelays
                   $Worksheet.Cells.Item($intRow,$intCol + 10).FormulaLocal = [string]$DHCPServerData.DHCPScopeSubnets
                  
                  
                  
                }else{
               
                    Write-Host "Populating Excel with DHCP Server $DHCPServer Data...." -ForegroundColor DarkGreen
                   
                   $Worksheet.Cells.Item($intRow,$intCol).FormulaLocal = $DHCPServerData.DHCPServerName
                   $Worksheet.Cells.Item($intRow,$intCol + 1).FormulaLocal = $DHCPServerData.DHCPDiscovers
                   $Worksheet.Cells.Item($intRow,$intCol + 2).FormulaLocal = $DHCPServerData.DHCPOffers
                   $Worksheet.Cells.Item($intRow,$intCol + 3).FormulaLocal = $DHCPServerData.DHCPDelayedOffer
                   $Worksheet.Cells.Item($intRow,$intCol + 4).FormulaLocal = $DHCPServerData.DHCPAcks
                   $Worksheet.Cells.Item($intRow,$intCol + 5).FormulaLocal = $DHCPServerData.DHCPNaks
                   $Worksheet.Cells.Item($intRow,$intCol + 6).FormulaLocal = $DHCPServerData.DHCPDeclines
                   $Worksheet.Cells.Item($intRow,$intCol + 7).FormulaLocal = $DHCPServerData.DHCPReleases
                   $Worksheet.Cells.Item($intRow,$intCol + 8).FormulaLocal = $DHCPServerData.DHCPScopes
                   $Worksheet.Cells.Item($intRow,$intCol + 9).FormulaLocal = $DHCPServerData.DHCPScopeDelays
                   $Worksheet.Cells.Item($intRow,$intCol + 10).FormulaLocal = [string]$DHCPServerData.DHCPScopeSubnets
               
                }
               
                $intRow +=1
               
           
            }
            catch
            {
                Write-Host "Error Occured" -ForegroundColor Red
           
            }
           
    }
   
    $Workbook.Worksheets.Item("Sheet1").Delete()
    $Workbook.Worksheets.Item("Sheet2").Delete()
    $Workbook.Worksheets.Item("Sheet3").Delete()
    Write-Host "Finished Collecting DHCP Server Data" -ForegroundColor Blue
 }
 
#endregion


Enjoy. As always please leave your comments about the topic at hand.
CollectDHCPInformation.ps1 (9.9KB)

Powershell: Configure DNS servers using Powershell

Hi Guys,

It's been sometime and I haven't really had anytime to post new articles. So I've got some time now.

Lately I've been ad many new client sites working on Active Directory and DNS. The current tasks i'm performing now is re-designing an Active directory infrastructure and DNS hierarchy.

In this post we will focus on DNS.

One the things I've being doing alot is configuring DNS, updating DNS information. Since I'm a very big fan of automation, I decide to automate most of the common stuff with DNS.

The below script will configue/create zones both forward and reverse lookup zones. It will also create conditional forwarders, etc. The script has helped me speed up a lot of repeated tasks and has also helped me collect some critical information, which is helping out with my design.

The script will run on Windows Server 2003/2008/2008 R2/2012/2012 R2

Anyway guys enjoy the script.

UPDATE: Hi Guys, I've updated the script with some really great features

#region "Hekp and Information"

<#
.SYNOPSIS
  Automated process of managing and editing DNS Servers

.DESCRIPTION
  The Script will allow you to manage and edit DNS Servers. Create/Delete Zones, Create/Delete Conditional Forwarders. Update/Remove DNS Forwarders
  Display DNS Statistics, etc. The script will also allow the DNS Administrator to populate Reverse-Lookup Zones straight from Active
  Directory Sites and services, by reading and anlysing the subnet information.

  It will also collect advanced DNS statistical information such as DNS memory Usage, DSN time, DNS Database information etc.

  Steps for Creating Conditional Forwarders:

  The script will process a CSV file, with headings ZoneNames and IP and the CSV file format should be similar to what's below.

    ZoneName,IP
    demo1.local, 10.10.10.1 10.10.10.2
    demo2.local, 10.10.11.1
    demo3.com.au, 10.10.12.1 10.10.12.2 10.10.12.3

 Steps to Adding DNS Forwaders:

 The script will process a CSV file, with headings DNSServer and ForwarderIP and the CSV file format should be similar to what's below.

    DNSServer,ForwaderIP
    Server1,10.10.10.1 10.10.10.2
    Server2,10.10.10.3 10.10.10.4
    Server3,10.100.4.10 10.100.6.10

 
 Steps to Gather DNS Statistics

 The script will process a CSV file, with heading DNSServer, the CSV file format should be similar to what's below. If no
 CSV file is specified, it will perform the query on the local DNS Server.

    DNSServer
    Server1
    Server2
    Server3

 Steps to Gather DNS Information

 The script will process a CSV file, DNS Server Names, the CSV file format should be similar to what's below. If no
 CSV file is specified, it will perform the query on the local DNS Server.

    DNSServer
    Server1
    Server2
    Server3


 Steps to Add New Forward-Lookup Zone

 The script will process a CSV file, with heading ZoneName, the CSV file format should be similar to what's below.

    ZoneName
    ZoneTest.local
    ZoneTest2.local
    ZoneTest3.local


 Steps to Add New Reverse-Lookup Zone

 The script will process a CSV file, with heading ReverseZoneName, the CSV file format should be similar to what's below.

    ZoneName
    192.168.0.20
    10.250.251.50
    10.251.252.50
    132.11.90.15



 Steps to Delete Zone(s)

 The script will process a CSV file, with heading ZoneName, the CSV file format should be similar to what's below.
 If the CSV file doesn't end in ".csv" the script will assume you are deleteing a single zone (Backup your zones before deleting them).

 NOTE: When deleting zones they are completely deleted including when it's Active Directory Integrated.

    ZoneName
    ZoneTest.local
    ZoneTest2.local
    ZoneTest3.local
 

 Note: The Script assumes that everything is Active-Directory Integrated

.EXAMPLE
  Creates a DNS Conditional Forwarder

  Configure-DNS.ps1 -CreateConditionalForwarder $true -CSVFile "C:\Temp\Test.csv"

.EXAMPLE
   Turn Off DNS Root hints

   Configure-DNS.ps1 -ConfigureRootHints $true -RootHintsOff $true

   Turn On DNS Root hints

   Configure-DNS.ps1 -ConfigureRootHints $true -RootHintsOff $false

.EXAMPLE
    Add New DNS Fordwaders, Flush Out the existing forwaders also disable Root Hints

    Configure-DNS.ps1 -AddForwarder $true -FlushForwarder $true -ForwarderCSVFile "C:\Temp\Forwaders.csv" -ConfigureRootHints $true -RootHintsOff $true

.EXAMPLE
    Get DNS Statistics of local DNS Server

    Configure-DNS.ps1 -GetDnsStats $true

   
    Get DNS Statistics of Multiple DNS servers

    Configure-DNS.ps1 -GetDnsStats $true -CSVFile "C:\Temp\DNSServer.csv"

.EXAMPLE
    Get DNS Memory Statistics of local DNS Server

    Configure-DNS.ps1 -GetDnsStats $true -DnsStatType Memory

   
    Get DNS Memory Statistics of Multiple DNS servers

    Configure-DNS.ps1 -GetDnsStats $true -CSVFile "C:\Temp\DNSServers.csv" -DnsStatType Memory

.EXAMPLE
    Get DNS Database Statistics of local DNS Server

    Configure-DNS.ps1 -GetDnsStats $true -DnsStatType Dbase

   
    Get DNS Database Statistics of Multiple DNS servers

    Configure-DNS.ps1 -GetDnsStats $true -CSVFile "C:\Temp\DNSServers.csv" -DnsStatType Dbase

.EXAMPLE
    Get DNS Information of local DNS Server

    Configure-DNS.ps1 -GetDnsInfo $true

   
    Get DNS Information of Multiple DNS servers

    Configure-DNS.ps1 -GetDnsInfo $true -CSVFile "C:\Temp\DNSServer.csv"

.EXAMPLE
    Backup Local DNS server (NOTE: For the backup to work you need to run the script as "Administrator" i.e. RunAs Administrator)
    The backup will initially create a folder with the server name under C:\. Once the backup starts it will copy all dns information to this folder.
    NOTE: All DNS Zones will be intially backed up to %SystemRoot%\System32\Dns\backup

    Configure-DNS.ps1 -BackUpDNS $true

.EXAMPLE
    Restore DNS server (NOTE: For the restore to work you need to run the script as "Administrator" i.e. RunAs Administrator)
    The Restore will look for the folder created when using the backup parameter i.e. Configure-DNS.ps1 -BackUpDNS $true
    It will get the and restore zones based on whats been captured via the csv file, and all records will be restored from the %SystemRoot%\System32\Dns\backup

    Configure-DNS.ps1 -RestoreDNS $true

.EXAMPLE
    Import DNS Record of Type 'PTR' (NOTE: The script will import 'PTR' records stored in a CSV file. Make sure the CSV file is named as the reverse-lookup zone
    eg: If the reverse zone is called 0.0.50.in-addr.arpa then the csv file should be named 0.0.50.in-addr.arpa.csv, otherwise it will not process the PTR records.)

    Configure-DNS.ps1 -PopulateDNSRecords $true -DnsRecordType PTR -RecordsCSVPath "C:\CSvprocessing

.EXAMPLE
    Import DNS Record of Type 'A' (NOTE: The script will import 'A' records stored in a CSV file. Make sure the CSV file is named as the domain
    eg: If the domain is called contoso.com then the csv file should be named contoso.com.csv, otherwise it will not process the A records.)
   
    Configure-DNS.ps1 -PopulateDNSRecords $true -DnsRecordType A -RecordsCSVPath "C:\CSvprocessing

.EXAMPLE
    Add a New Forward lookup Zone with Secure Dynamic Updates

    Configure-DNS.ps1 -NewForwardZone $true -AllowDynamicUpdates $true -ZoneCSVFile "C:\Temp\ForwardZones.csv"

.EXAMPLE
    Add a New Reverse lookup Zone with Secure Dynamic Updates

    Configure-DNS.ps1 -NewReverseZone $true -AllowDynamicUpdates $true -ZoneCSVFile "C:\Temp\ReverseZones.csv"

.EXAMPLE
    Restore DNS records. The script will restore Dns Records (Only PTR Records at the moment), the Dns records need to be exported out as CSV files with comma delimetered.
    If you have mutiple exported csv files with Dns records, each CSV file will be processed one at a time.

    Configure-DNS.ps1 -PopulateDNSRecords $true -DnsRecordType PTR -RecordsCSVPath "C:\CSvprocessing"

.EXAMPLE
    Delete a Forward-Lookup Zone from a CSV File

    Configure-DNS.ps1 -DeleteZone $true -DeleteZoneNameOrCSV "C:\Temp\DeleteZones.csv" -GetZoneType Forward

    Delete a Reverse-Lookup Zone from a CSV File

    Configure-DNS.ps1 -DeleteZone $true -DeleteZoneNameOrCSV "C:\Temp\DeleteZones.csv" -GetZoneType Reverse

.EXAMPLE
    Delete a Single Forward-Lookup Zone

    Configure-DNS.ps1 -DeleteZone $true -DeleteZoneNameOrCSV "samplezone.local"

    Delete a Single Reverse-Lookup Zone

    Configure-DNS.ps1 -DeleteZone $true -DeleteZoneNameOrCSV "192.168.0.0"

.EXAMPLE
    Enumerate all Zones

    Configure-DNS.ps1 -GetAllZones $true

.EXAMPLE
    Enumerate all Zones including AutoCreated Zones

    Configure-DNS.ps1 -GetAllZones $true -AutoCreatedZones $true

.EXAMPLE
    Enumerate all Forward-Lookup Zones

    Configure-DNS.ps1 -GetAllZones $true -GetZoneType Forward

.EXAMPLE
    Enumerate all Forward Zones including AutoCreated Zones

    Configure-DNS.ps1 -GetAllZones $true -GetZoneType Forward -AutoCreatedZones $true

.EXAMPLE
    Enumerate all Reverse Zones

    Configure-DNS.ps1 -GetAllZones $true -GetZoneType Reverse

.EXAMPLE
    Enumerate all Reverse Zones including AutoCreated Zones

    Configure-DNS.ps1 -GetAllZones $true -GetZoneType Reverse -AutoCreatedZones $true

.EXAMPLE
    Get Zone Information

    Configure-DNS.ps1 -GetZoneInfo $true -NameOfZone contoso.com.au

.EXAMPLE
    Configure-DNS.ps1 now can populate DNS Reverse zones straight from Active Directory Sites and Services. The Script will
    connect to Active Directory and collect information about every subnet available and then it will check DNS to see if that subnet is available as
    a Class A, Class B or Class C subnet. If the subnet doesn't exist it will then create that reverse zone.

    Configure a Class A Subnet from Active directory with Secure Dynamic Updates

    Configure-DNS.ps1 -PopulateFromAD $true -AllowDynamicUpdates $true -SubNetClass ClassA

    Configure a Class B Subnet from Active directory with Secure Dynamic Updates

    Configure-DNS.ps1 -PopulateFromAD $true -AllowDynamicUpdates $true -SubNetClass ClassB

    Configure a Class C Subnet from Active directory with Secure Dynamic Updates

    Configure-DNS.ps1 -PopulateFromAD $true -AllowDynamicUpdates $true -SubNetClass ClassC

.EXAMPLE
    Enable Aging on DNS Servers and Zones

    Configure-DNS.ps1 -DnsZoneAging $true -EnableAging $true -AllActiveDnsServers $true

.EXAMPLE
    Disable Aging on DNS Servers and Zones

    Configure-DNS.ps1 -DnsZoneAging $true -AllActiveDnsServers $true

.EXAMPLE
    Repair DNS SRV and Name Server Records

    Configure-DNS.ps1 -RepairDnsRecords $true


  
.NOTES
   Version 1.0: Disable DNS root hints
   Version 1.1: Create new Conditional Forwarders
   Version 1.2: Add New DNS Forwarders, DNS Statistics, and DNS Info
   Version 1.3: Backup and Restore DNS
   version 1.4: Adding of both Forward/Reverse lookup zones
   version 1.5: Deleting Zones, Enumerating Zones
   version 1.6: Add Dns Records (PTR records only at the moment), Collect Zone Information
   version 1.7: Populate DNS Reverse-Zones staright from Active Directory
   Version 1.8: Enable/Disable Aging and Scavenging on DNS Servers and on Zones
   Version 1.9: Repair DNS Records
   ToDo's: Many more features coming soon...
   Written by Michael Aksoy
   Date: 12.03.2014
  
 
#>

#endregion

#region "Parameters for Script"
param
(
    [Parameter(Mandatory=$false)]
    [bool]$ConfigureRootHints=$false,
    [Parameter(Mandatory=$false)]
    [bool]$RootHintsOff=$false,
    [Parameter(Mandatory=$false)]
    [bool]$CreateConditionalForwarder=$false,
    [Parameter(Mandatory=$false)]
    [string]$CSVFile="",
    [Parameter(Mandatory=$false)]
    [bool]$AddForwarder=$false,
    [Parameter(Mandatory=$false)]
    [bool]$FlushForwarder=$false,
    [Parameter(Mandatory=$false)]
    [string]$ForwarderCSVFile="",
    [Parameter(Mandatory=$false)]
    [bool]$GetDnsStats=$false,
    [ValidateSet("Time","Master","Secondary", "Ds", "Dbase", "Memory", "PacketMemory", "NbStatMem", "Records")]
    [Parameter(Mandatory=$false)]
    [string]$DnsStatType = "",
    [Parameter(Mandatory=$false)]
    [bool]$GetDnsInfo=$false,
    [Parameter(Mandatory=$false)]
    [bool]$BackUpDNS=$false,
    [Parameter(Mandatory=$false)]
    [bool]$RestoreDNS=$false,
    [Parameter(Mandatory=$false)]
    [bool]$NewForwardZone = $false,
    [Parameter(Mandatory=$false)]
    [bool]$NewReverseZone = $false,
    [Parameter(Mandatory=$false)]
    [bool]$AllowDynamicUpdates = $false,
    [Parameter(Mandatory=$false)]
    [string]$ZoneCSVFile="",
    [Parameter(Mandatory=$false)]
    [bool]$DeleteZone = $false,
    [Parameter(Mandatory=$false)]
    [string]$DeleteZoneNameOrCSV = "",
    [Parameter(Mandatory=$false)]
    [bool]$GetAllZones = $false,
    [ValidateSet("Forward","Reverse")]
    [Parameter(Mandatory=$false)]
    [string]$GetZoneType = "",
    [Parameter(Mandatory=$false)]
    [bool]$AutoCreatedZones = $false,
    [Parameter(Mandatory=$false)]
    [bool]$PopulateDNSRecords = $false,
    [Parameter(Mandatory=$false)]
    [string]$RecordsCSVPath = "",
    [ValidateSet("A-Record","PTR")]
    [Parameter(Mandatory=$false)]
    [string]$DnsRecordType = "",
    [Parameter(Mandatory=$false)]
    [bool]$GetZoneInfo = $false,
    [Parameter(Mandatory=$false)]
    [string]$NameOfZone = "",
    [Parameter(Mandatory=$false)]
    [bool]$PopulateFromAD = $false,
    [ValidateSet("ClassA","ClassB", "ClassC")]
    [Parameter(Mandatory=$false)]
    [string]$SubNetClass = "",
    [Parameter(Mandatory=$false)]
    [bool]$DnsZoneAging = $false,
    [Parameter(Mandatory=$false)]
    [bool]$EnableAging = $false,
    [Parameter(Mandatory=$false)]
    [string]$DnsServerName = "",
    [Parameter(Mandatory=$false)]
    [bool]$AllActiveDnsServers = $false,
    [Parameter(Mandatory=$false)]
    [bool]$RepairDnsRecords = $false
     
)

#endregion

#region "Complete DNS Script"
#region "Script Functions"

Function Search-AD
{

    param (
        [string[]]$Filter,
        [string[]]$Properties = @('Name','ADSPath'),
        [string]$SearchRoot,
        [switch]$DontJoinAttributeValues
    )
    if ($SearchRoot)
    {
        $Root = [ADSI]$SearchRoot
    }
    else
    {
        $Root = [ADSI]''
    }
    if ($Filter)
    {
        $LDAP = "(&({0}))" -f ($Filter -join ')(')
    }
    else
    {
        $LDAP = "(name=*)"
    }
    try
    {
        (New-Object ADSISearcher -ArgumentList @(
            $Root,
            $LDAP,
            $Properties
        ) -Property @{
            PageSize = 1000
        }).FindAll() | ForEach-Object {
            $ObjectProps = @{}
            $_.Properties.GetEnumerator() |
                Foreach-Object {
                    $Val = @($_.Value)
                    if ($_.Name -ne $null)
                    {
                        if ($DontJoinAttributeValues -and ($Val.Count -gt 1))
                        {
                            $ObjectProps.Add(
                                $_.Name,
                                ($_.Value)
                            )
                        }
                        else
                        {
                            $ObjectProps.Add(
                                $_.Name,
                                (-join $_.Value)
                            )
                        }
                    }
                }
            if ($ObjectProps.psbase.keys.count -ge 1)
            {
                New-Object PSObject -Property $ObjectProps |
                    select $Properties
            }
        }
    }
    catch
    {

        Write-Warning -Message ('Search-AD: Filter - {0}: Root - {1}: Error - {2}' -f $LDAP,$Root.Path,$_.Exception.Message) | Out-String | Add-Content $LogFile
    }
}


 
#---------------------------------------------------
# Compute the subnet/prefix length
#---------------------------------------------------
function Compute-Prefix ( $IntStart, $IntEnd, $SubnetType )
{
    if ( $SubnetType -eq "IPv4" )
    {
        [Double] $NumberOfIPs = [Double] $IntEnd - [Double] $IntStart
    }
    else
    {
        [System.Numerics.BigInteger] $NumberOfIPs = [System.Numerics.BigInteger] $IntEnd - [System.Numerics.BigInteger] $IntStart
    }
    
    $IPlength = [Math]::Ceiling([Math]::Log($NumberOfIPs,2))
    $Prefix = 32 - $IPlength
    Return $Prefix
}


Function ConvertTo-BinaryIP {
<#
    .Synopsis
      Converts a Decimal IP address into a binary format.
    .Description
      ConvertTo-BinaryIP uses System.Convert to switch between decimal and binary format. The output from this function is dotted binary.
    .Parameter IPAddress
      An IP Address to convert.
  #>

  Param(
    [Parameter(Mandatory = $True)]
    [Net.IPAddress]$IPAddress
  )

  Return [String]::Join('.', $( $IPAddress.GetAddressBytes() |
      ForEach-Object { [Convert]::ToString($_, 2).PadLeft(8, '0') } ))


}


Function ConvertTo-DecimalIP {
  <#
    .Synopsis
      Converts a Decimal IP address into a 32-bit unsigned integer.
    .Description
      ConvertTo-DecimalIP takes a decimal IP, uses a shift-like operation on each octet and returns a single UInt32 value.
    .Parameter IPAddress
      An IP Address to convert.
  #>
 
  Param(
    [Parameter(Mandatory = $True)]
    [Net.IPAddress]$IPAddress
  )
 
 
    $i = 3; $DecimalIP = 0;
    $IPAddress.GetAddressBytes() | ForEach-Object { $DecimalIP += $_ * [Math]::Pow(256, $i); $i-- }
 
    Return [UInt32]$DecimalIP
 
}

Function ConvertTo-DottedDecimalIP {

 <#
    .Synopsis
      Returns a dotted decimal IP address from either an unsigned 32-bit integer or a dotted binary string.
    .Description
      ConvertTo-DottedDecimalIP uses a regular expression match on the input string to convert to an IP address.
    .Parameter IPAddress
      A string representation of an IP address from either UInt32 or dotted binary.
  #>


  Param(
    [Parameter(Mandatory = $True)]
    [String]$IPAddress
  )

  Switch -RegEx ($IPAddress) {
      "([01]{8}.){3}[01]{8}" {
        Return [String]::Join('.', $( $IPAddress.Split('.') | ForEach-Object { [Convert]::ToUInt32($_, 2) } ))
      }
      "d" {
        $IPAddress = [UInt32]$IPAddress
        $DottedIP = $( For ($i = 3; $i -gt -1; $i--) {
          $Remainder = $IPAddress % [Math]::Pow(256, $i)
          ($IPAddress - $Remainder) / [Math]::Pow(256, $i)
          $IPAddress = $Remainder
         } )
      
        Return [String]::Join('.', $DottedIP)
      }
      default {
        Write-Error "Cannot convert this format"
      }
    }

}


Function ConvertTo-MaskLength {

<#
    .Synopsis
      Returns the length of a subnet mask.
    .Description
      ConvertTo-MaskLength accepts any IPv4 address as input, however the output value
      only makes sense when using a subnet mask.
    .Parameter SubnetMask
      A subnet mask to convert into length
  #>

Param(
    [Parameter(Mandatory = $True)]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask
  )

  $Bits = "$( $SubnetMask.GetAddressBytes() | ForEach-Object { [Convert]::ToString($_, 2) } )" -Replace '[s0]'
 
  Return $Bits.Length
}


Function ConvertTo-Mask {

<#
    .Synopsis
      Returns a dotted decimal subnet mask from a mask length.
    .Description
      ConvertTo-Mask returns a subnet mask in dotted decimal format from an integer value ranging
      between 0 and 32. ConvertTo-Mask first creates a binary string from the length, converts
      that to an unsigned 32-bit integer then calls ConvertTo-DottedDecimalIP to complete the operation.
    .Parameter MaskLength
      The number of bits which must be masked.
  #>


  Param(
    [Parameter(Mandatory = $True)]
    [Alias("Length")]
    [ValidateRange(0, 32)]
    $MaskLength
  )

  Return ConvertTo-DottedDecimalIP ([Convert]::ToUInt32($(("1" * $MaskLength).PadRight(32, "0")), 2))


}


Function Get-NetworkAddress {
 <#
    .Synopsis
      Takes an IP address and subnet mask then calculates the network address for the range.
    .Description
      Get-NetworkAddress returns the network address for a subnet by performing a bitwise AND
      operation against the decimal forms of the IP address and subnet mask. Get-NetworkAddress
      expects both the IP address and subnet mask in dotted decimal format.
    .Parameter IPAddress
      Any IP address within the network range.
    .Parameter SubnetMask
      The subnet mask for the network.
  #>


  Param(
    [Parameter(Mandatory = $True, Position = 0)]
    [Net.IPAddress]$IPAddress,
   
    [Parameter(Mandatory = $True, Position = 1)]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask
    )

    Return ConvertTo-DottedDecimalIP ((ConvertTo-DecimalIP $IPAddress) -BAnd (ConvertTo-DecimalIP $SubnetMask))
}

Function Get-BroadcastAddress {

<#
    .Synopsis
      Takes an IP address and subnet mask then calculates the broadcast address for the range.
    .Description
      Get-BroadcastAddress returns the broadcast address for a subnet by performing a bitwise AND
      operation against the decimal forms of the IP address and inverted subnet mask.
      Get-BroadcastAddress expects both the IP address and subnet mask in dotted decimal format.
    .Parameter IPAddress
      Any IP address within the network range.
    .Parameter SubnetMask
      The subnet mask for the network.
  #>

    Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [Net.IPAddress]$IPAddress,
   
    [Parameter(Mandatory = $True, Position = 1)]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask
  )

  Return ConvertTo-DottedDecimalIP $((ConvertTo-DecimalIP $IPAddress) -BOr ((-BNot (ConvertTo-DecimalIP $SubnetMask)) -BAnd [UInt32]::MaxValue))

}


Function Get-NetworkRange {

<#
    .Synopsis
      Generates IP addresses within the specified network.
    .Description
      Get-NetworkRange finds the network and broadcast address as decimal values then starts a
      counter between the two, returning Net.IPAddress for each.
    .Parameter IPAddress
      Any IP address within the network range.
    .Parameter Network
      A network description in the format 1.2.3.4/24
    .Parameter SubnetMask
      The subnet mask for the network.
  #>

Param(
    [Parameter(Mandatory = $True, Position = 0, ParameterSetName = "IPAndMask")]
    [Net.IPAddress]$IPAddress,
   
    [Parameter(Mandatory = $True, Position = 1, ParameterSetName = "IPAndMask")]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask,
   
    [Parameter(Mandatory = $True, ParameterSetName = "CIDRNotation")]
    [ValidatePattern('^(d{1,3}.){3}d{1,3}[\/]d{1,2}$')]
    [String]$Network
  )


If ($PsCmdLet.ParameterSetName -eq 'CIDRNotation') {
      $Temp = $Network.Split("/")
      $IPAddress = $Temp[0]
      $SubnetMask = ConvertTo-Mask $Temp[1]
    }
 
    $DecimalIP = ConvertTo-DecimalIP $IPAddress
    $DecimalMask = ConvertTo-DecimalIP $SubnetMask
 
    $DecimalNetwork = $DecimalIP -BAnd $DecimalMask
    $DecimalBroadcast = $DecimalIP -BOr ((-BNot $DecimalMask) -BAnd [UInt32]::MaxValue)
 
    For ($i = $($DecimalNetwork + 1); $i -lt $DecimalBroadcast; $i++) {
      ConvertTo-DottedDecimalIP $i
    }

}


Function Get-NetworkSummary {

<#
    .Synopsis
      Generates a summary of a network range
    .Description
      Get-NetworkSummary uses most of the IP conversion CmdLets to provide a summary of a network
      range from any IP address in the range and a subnet mask.
    .Parameter IPAddress
      Any IP address within the network range.
    .Parameter Network
      A network description in the format 1.2.3.4/24
    .Parameter SubnetMask
      The subnet mask for the network.
  #>

  Param(
    [Parameter(Mandatory = $True, Position = 0, ParameterSetName = "IPAndMask")]
    [Net.IPAddress]$IPAddress,
   
    [Parameter(Mandatory = $True, Position = 1, ParameterSetName = "IPAndMask")]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask,
   
    [Parameter(Mandatory = $True, ParameterSetName = "CIDRNotation")]
    [ValidatePattern('^(d{1,3}.){3}d{1,3}[\/]d{1,2}$')]
    [String]$Network
  )


  If ($PsCmdLet.ParameterSetName -eq 'CIDRNotation') {
      $Temp = $Network.Split("/")
      $IPAddress = $Temp[0]
      $SubnetMask = ConvertTo-Mask $Temp[1]
    }
 
    $DecimalIP = ConvertTo-DecimalIP $IPAddress
    $DecimalMask = ConvertTo-DecimalIP $SubnetMask
    $DecimalNetwork =  $DecimalIP -BAnd $DecimalMask
    $DecimalBroadcast = $DecimalIP -BOr ((-BNot $DecimalMask) -BAnd [UInt32]::MaxValue)
 
    $NetworkSummary = New-Object PSObject -Property @{
      "NetworkAddress"   = (ConvertTo-DottedDecimalIP $DecimalNetwork);
      "NetworkDecimal"   = $DecimalNetwork
      "BroadcastAddress" = (ConvertTo-DottedDecimalIP $DecimalBroadcast);
      "BroadcastDecimal" = $DecimalBroadcast
      "Mask"             = $SubnetMask;
      "MaskLength"       = (ConvertTo-MaskLength $SubnetMask);
      "MaskHexadecimal"  = (ConvertTo-HexIP $SubnetMask);
      "HostRange"        = "";
      "NumberOfHosts"    = ($DecimalBroadcast - $DecimalNetwork - 1);
      "Class"            = "";
      "IsPrivate"        = $False}
 
    If ($NetworkSummary.MaskLength -lt 31) {
      $NetworkSummary.HostRange = [String]::Format("{0} - {1}",
        (ConvertTo-DottedDecimalIP ($DecimalNetwork + 1)),
        (ConvertTo-DottedDecimalIP ($DecimalBroadcast - 1)))
    }
 
    Switch -RegEx ($(ConvertTo-BinaryIP $IPAddress)) {
      "^1111"              { $NetworkSummary.Class = "E" }
      "^1110"              { $NetworkSummary.Class = "D" }
      "^11000000.10101000" { $NetworkSummary.Class = "C"; $NetworkSummary.IsPrivate = $True }
      "^110"               { $NetworkSummary.Class = "C" }
      "^10101100.0001"     { $NetworkSummary.Class = "B"; $NetworkSummary.IsPrivate = $True }
      "^10"                { $NetworkSummary.Class = "B" }
      "^00001010"          { $NetworkSummary.Class = "A"; $NetworkSummary.IsPrivate = $True }
      "^0"                 { $NetworkSummary.Class = "A" }
    }  
 
    Return $NetworkSummary

}

Function ConvertTo-HexIP {
  <#
    .Synopsis
      Converts a dotted decimal IP address into a hexadecimal string.
    .Description
      ConvertTo-HexIP takes a dotted decimal IP and returns a single hexadecimal string value.
    .Parameter IPAddress
      An IP Address to convert.
  #>

  Param(
    [Parameter(Mandatory = $True)]
    [Net.IPAddress]$IPAddress
  )

  Return "$($IPAddress.GetAddressBytes() | ForEach-Object { '{0:x2}' -f $_ })" -Replace 's'
}


Function ConvertFrom-HexIP {

<#
    .Synopsis
      Converts a hexadecimal IP address into a dotted decimal string.
    .Description
      ConvertFrom-HexIP takes a hexadecimal string and returns a dotted decimal IP address.
    .Parameter IPAddress
      An IP Address to convert.
  #>

  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [ValidatePattern('^[0-9a-f]{8}$')]
    [String]$IPAddress
  )

  Return ConvertTo-DottedDecimalIP ([Convert]::ToUInt32($IPAddress, 16))


}


Function Get-Subnets {

<#
    .Synopsis
      Generates a list of subnets for a given network range
    .Description
      Generates a list of subnets for a given network range using either the address class or a
      user-specified value.
    .Parameter NetworkAddress
      Any address in the supernet range.
    .Parameter SubnetMask
      The desired mask, determines the size of the resulting subnet. Must be a valid subnet mask.
    .Parameter SupernetLength
      By default Get-Subnets uses the address class to determine the size of the supernet. Where the
      supernet describes the range of addresses being split.
  #>


Param(
    [Parameter(Mandatory = $True, Position = 0, ParameterSetName = "IPAndMask")]
    [Net.IPAddress]$IPAddress,
   
    [Parameter(Mandatory = $True, Position = 1, ParameterSetName = "IPAndMask")]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask,
   
    [Parameter(Mandatory = $True, ParameterSetName = "CIDRNotation")]
    [ValidatePattern('^(d{1,3}.){3}d{1,3}[\/]d{1,2}$')]
    [String]$Network,
 
    [ValidateRange(1, 32)]
    [UInt32]$SupernetLength
  )

  If ($PsCmdLet.ParameterSetName -eq 'CIDRNotation') {
      $Temp = $Network.Split("/")
      $IPAddress = $Temp[0]
      $SubnetMask = ConvertTo-Mask $Temp[1]
    } Else {
      $SubnetLength = ConvertTo-MaskLength $SubnetMask
    }
 
    If (!$SupernetLength) {
      $SupernetLength = Switch -RegEx ($(ConvertTo-BinaryIP $IPAddress)) {
        "^110"  { 24 }
        "^10"   { 16 }
        "^0"    { 8 }
        default { 24 }
      }
    }
    If ($SupernetLength -gt $SubnetLength) {
      Write-Error "Subnet is larger than supernet. Aborting"
    }
    $SupernetMask = ConvertTo-Mask $SupernetLength
 
    $NumberOfNets = [Math]::Pow(2, ($SubnetLength - $SupernetLength))
    $NumberOfAddresses = [Math]::Pow(2, (32 - $SubnetLength))
 
    $SupernetAddress = Get-NetworkAddress $IPAddress $SupernetMask
    $DecimalAddress = ConvertTo-DecimalIP $SupernetAddress
 
    For ($i = 0; $i -lt $NumberOfNets; $i++) {
      $NetworkAddress = ConvertTo-DottedDecimalIP $DecimalAddress
 
      "" | Select-Object @{n='NetworkAddress';e={ $NetworkAddress }},
        @{n='BroadcastAddress';e={ Get-BroadcastAddress $NetworkAddress $SubnetMask }},
        @{n='SubnetMask';e={ $SubnetMask }},
        @{n='HostAddresses';e={
          $NumberOfHosts = $NumberOfAddresses - 2
          If ($NumberOfHosts -lt 0) { 0 } Else { $NumberOfHosts } }}
 
      $DecimalAddress += $NumberOfAddresses
    }
}



#endregion

CLS #Clear Screen

$TimeVal = Get-Date -uformat "%Y-%m-%d-%H-%M"
$CurrentDate = Get-Date -Format d
$CurrentDay = (Get-Date).DayOfWeek.ToString()
$LogDir = "C:\Logs\"
$LogFileName = $CurrentDay + "_DNSLogs.txt"
$LogFile = $LogDir + $LogFileName

Write-Host "`nSetting LogPath to $LogDir" -ForegroundColor Green
IF (!(Test-Path $LogDir)) {new-item -type Directory -path $LogDir} 

Write-Output "********************************************************************** Logging Started *****************************************************************" | Add-Content $LogFile

#region "Create Condintional Forwarders"
if($CreateConditionalForwarder -eq $true)
{

    $CSVToProcess = $CSVFile
   
    #$csvFile ="C:\Temp\DNSForwarder.csv"

    Write-Host ""
    Write-Host "Processing CSV file $CSVToProcess.... Importing Conditional Forwarder Information" -ForegroundColor Green
    Write-Host ""
    Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing Conditional Forwarder Information" | Add-Content $LogFile


    Import-Csv $CSVToProcess | ForEach-Object {

        $ForwarderZoneName ="$($_.ZoneName)" # Zone name of  DNS Conditional Forwarder
        $ForwarderIP =$_.IP   # Forwarder IP Address


        try{

            #dnscmd /ZoneAdd $ForwarderZoneName /Dsforwarder $ForwarderIP
            $cmd = "dnscmd /ZoneAdd $ForwarderZoneName /Dsforwarder $ForwarderIP"
            Invoke-Expression $cmd | Out-String | Add-Content $LogFile

            Write-Host "`nConditional Forwarder $ForwarderZoneName has been created with Forwarder IP $ForwarderIP" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Conditional Forwarder $ForwarderZoneName has been created with Forwarder IP $ForwarderIP" | Add-Content $LogFile

        }
        catch [Exception]
        {
            Write-Host "`nUnable create Conditional Forwarder $ForwarderZoneName. An error has occured" -ForegroundColor Red
            Write-Output "n$CurrentDate --> Unable create Conditional Forwarder $ForwarderZoneName. An error has occured" | Add-Content $LogFile
        }
   


    }

}

#endregion

#region "Add Forwarders to DNS Servers"
if($AddForwarder -eq $true)
{
   
    <#
         Use DnsCmd to add forwaders to DNS servers

         usage dnscmd <ServerName> /ResetForwarders <MasterIPAddress....> /[TimeOut <time> [/Slave]

         <ServerName> -->  Required. Specifies the DNS host name of the DNS server. You can also type the IP address of the DNS server. To specify the DNS server on the local computer, you can also type a period (.).

        /ResetForwarders --> Required. Configures a forwarder.

        <MasterIPaddress...> --> Required. Specifies a space-separated list of one or more IP addresses of the DNS servers where queries are forwarded. You may specify a list of space-separated IP addresses.

        /TimeOut --> Optional. Specifies the timeout setting. The timeout setting is the number of seconds before unsuccessful forward queries time out.

        <Time> --> Specifies the value for the /TimeOut parameter. The value is in seconds. The default timeout is five seconds.

        /Slave --> optional. Determines whether or not the DNS server uses recursion when it queries for the domain name that is specified by ZoneName.


   
    #>

    $CurrentIP = ""

    $CSVToProcess = $ForwarderCSVFile
    #$csvFile ="C:\Temp\DNSForwarder.csv"

    Write-Host ""
    Write-Host "`nProcessing CSV file $CSVToProcess.... Importing DNS and Forwarder Information" -ForegroundColor Green
    Write-Host ""
    Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing DNS and Forwarder Information" | Add-Content $LogFile

    #Reset any Forwaders, which are not required.

    if($FlushForwarder -eq $true)
    {
        if($CSVToProcess -ne "")
        {
           
            Import-Csv $CSVToProcess | ForEach-Object {
                $DNSServer ="$($_.DNSServer)" # # DNS Server Name

                #dnscmd $DNSServer /ResetForwarders #Reset/Clear all Forwaders
                $cmd = "dnscmd $DNSServer /ResetForwarders"
                Invoke-Expression $cmd | Out-String | Add-Content $LogFile
                Write-Host "`nFlushing DNS Server $DNSServer Forwarders" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Flushing DNS Server $DNSServer Forwarders" | Add-Content $LogFile
            }
        }else{
            #dnscmd /ResetForwarders #Reset/Clear all Forwaders
            $cmd = "dnscmd /ResetForwarders"
            Invoke-Expression $cmd | Out-String | Add-Content $LogFile
            Write-Host "`nFlushing Local DNS Server $env:COMPUTERNAME Forwarders" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Flushing Local DNS Server $env:COMPUTERNAME Forwarders" | Add-Content $LogFile


        }
    }

    if($CSVToProcess -ne "")
    {
   
        Import-Csv $CSVToProcess | ForEach-Object {

            $DNSServer ="$($_.DNSServer)" # # DNS Server Name
            $ForwarderIP = $_.ForwaderIP   # Forwarder IP Address
       
            $CurrentIP = $ForwarderIP

            try{
           
                #$command = "C:\Windows\System32\dnscmd.exe $(hostname) /resetforwarders $forwardersip"
                # Default TimeOut for script is set to 5 Seconds

                 $command = "dnscmd.exe $DNSServer /ResetForwarders $ForwarderIP /Timeout 5"
                 Write-Host "`nExecuting DNSCMD command $command" -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Executing DNSCMD command $command" | Add-Content $LogFile

                 #Invoke-Expression -Command $command
                 Invoke-Expression -Command $command | Out-String | Add-Content $LogFile

                #dnscmd $DNSServer /ResetForwarders $CurrentIP /TimeOut 5 # Default DNS Response TimeOu 5 Seconds

                Write-Host "`nForwader IP $ForwarderIP has been added to DNS Server $DNSServer successfully" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Forwader IP $ForwarderIP has been added to DNS Server $DNSServer successfully" | Add-Content $LogFile

            }
            catch [Exception]
            {
                Write-Host "`nUnable Add Forwader IP $ForwarderIP to DNS Server $DNSServer. An error has occured" -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Unable Add Forwader IP $ForwarderIP to DNS Server $DNSServer. An error has occured" | Add-Content $LogFile
            }
   


        }

    }


}


#endregion

#region "Configure Root Hints for DNS"

#Enable or Disable "Use root hints if no forwarders are available"

if($ConfigureRootHints -eq $true)
{
    if($RootHintsOff -eq $false)
    {

        $CSVToProcess = $ForwarderCSVFile

        Write-Host ""
        Write-Host "Processing CSV file $CSVToProcess.... Importing!" -ForegroundColor Green
        Write-Host ""
        Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing!" | Add-Content $LogFile


        <#
            verification can be done by excuting dnscmd /info. The results will be similiar to whats below.

            Once dnscmd /info has been run, to verify that "Use root hints if no forwarders are available" has been turned On

            the flags fSlave = 0, and Slave = 0 (Or you can verify it using DNS Manager)

            ***** Results when executing dnscmd /info *******

             Server info
                server name              = Your DNS Server Name
                version                  = 1DB10106 (6.1 build 7601)
                DS container             = cn=MicrosoftDNS,cn=System,DC=domain,DC=com
                forest name              = Domain.com
                domain name              = Domain.com
                builtin forest partition = ForestDnsZones.domain.com
                builtin domain partition = DomainDnsZones.domain.com
                read only DC             = 0
                last scavenge cycle      = not since restart (0)
             Configuration:
                dwLogLevel               = 00000000
                dwDebugLevel             = 00000000
                dwRpcProtocol            = 00000005
                dwNameCheckFlag          = 00000002
                cAddressAnswerLimit      = 0
                dwRecursionRetry         = 3
                dwRecursionTimeout       = 8
                dwDsPollingInterval      = 180
             Configuration Flags:
                fBootMethod                  = 3
                fAdminConfigured             = 1
                fAllowUpdate                 = 1
                fDsAvailable                 = 1
                fAutoReverseZones            = 1
                fAutoCacheUpdate             = 0
                fSlave                       = 0
                fNoRecursion                 = 0
                fRoundRobin                  = 1
                fStrictFileParsing           = 0
                fLooseWildcarding            = 0
                fBindSecondaries             = 0
                fWriteAuthorityNs            = 0
                fLocalNetPriority            = 1
             Aging Configuration:
                ScavengingInterval           = 0
                DefaultAgingState            = 0
                DefaultRefreshInterval       = 168
                DefaultNoRefreshInterval     = 168
      ServerAddresses:

        Ptr          = 00000000003B2760
        MaxCount     = 1
        AddrCount    = 1
            Addr[0] => af=2, salen=16, [sub=0, flag=00000000] p=13568, addr=192.100.4.10

      ListenAddresses:
         NULL IP Array.
      Forwarders:
         NULL IP Array.
        forward timeout  = 3
        slave            = 0

        #>

        if($CSVToProcess -ne "")
        {

            Import-Csv $CSVToProcess | ForEach-Object {
                $DNSServer ="$($_.DNSServer)" # # DNS Server Name

                #Turn On Root Hints
                #dnscmd $DNSServer /config /isSlave 0 # For Remote Server: dnscmd RemoteServerName /config /isSlave 0
                $cmd = "dnscmd $DNSServer /config /isSlave 0"
                Invoke-Expression $cmd | Out-String | Add-Content $LogFile

                Write-Host "`nRoot Hints turned on DNS Server $DNSServer" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Root Hints turned on DNS Server $DNSServer" | Add-Content $LogFile

            }
        }else{

            #dnscmd /config /isSlave 0 # For Remote Server: dnscmd RemoteServerName /config /isSlave 0
            $cmd = "dnscmd /config /isSlave 0"
            Invoke-Expression $cmd | Out-String | Add-Content $LogFile
            Write-Host "`nRoot Hints turned on Local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Root Hints turned on Local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
        }
       


    }else{

       <#
            verification can be done by excuting dnscmd /info. The results will be similiar to whats below.

            Once dnscmd /info has been run, to verify that "Use root hints if no forwarders are available" has been turned Off

            the flags fSlave = 1, and Slave = 1 (Or you can verify it using DNS Manager)

            ***** Results when executing dnscmd /info *******

             Server info
                server name              = Your DNS Server Name
                version                  = 1DB10106 (6.1 build 7601)
                DS container             = cn=MicrosoftDNS,cn=System,DC=domain,DC=com
                forest name              = Domain.com
                domain name              = Domain.com
                builtin forest partition = ForestDnsZones.domain.com
                builtin domain partition = DomainDnsZones.domain.com
                read only DC             = 0
                last scavenge cycle      = not since restart (0)
             Configuration:
                dwLogLevel               = 00000000
                dwDebugLevel             = 00000000
                dwRpcProtocol            = 00000005
                dwNameCheckFlag          = 00000002
                cAddressAnswerLimit      = 0
                dwRecursionRetry         = 3
                dwRecursionTimeout       = 8
                dwDsPollingInterval      = 180
             Configuration Flags:
                fBootMethod                  = 3
                fAdminConfigured             = 1
                fAllowUpdate                 = 1
                fDsAvailable                 = 1
                fAutoReverseZones            = 1
                fAutoCacheUpdate             = 0
                fSlave                       = 1
                fNoRecursion                 = 0
                fRoundRobin                  = 1
                fStrictFileParsing           = 0
                fLooseWildcarding            = 0
                fBindSecondaries             = 0
                fWriteAuthorityNs            = 0
                fLocalNetPriority            = 1
             Aging Configuration:
                ScavengingInterval           = 0
                DefaultAgingState            = 0
                DefaultRefreshInterval       = 168
                DefaultNoRefreshInterval     = 168
      ServerAddresses:

        Ptr          = 00000000003B2760
        MaxCount     = 1
        AddrCount    = 1
            Addr[0] => af=2, salen=16, [sub=0, flag=00000000] p=13568, addr=192.100.4.10

      ListenAddresses:
         NULL IP Array.
      Forwarders:
         NULL IP Array.
        forward timeout  = 3
        slave            = 1

        #>

        if($CSVToProcess -ne "")
        {

            Import-Csv $CSVToProcess | ForEach-Object {
                $DNSServer ="$($_.DNSServer)" # # DNS Server Name

                 #Turn Off Root Hints
                 #dnscmd $DNSServer /config /isSlave 1 # For Remote Server: dnscmd RemoteServerName /config /isSlave 1
                 $cmd = "dnscmd $DNSServer /config /isSlave 1"
                 Invoke-Expression $cmd | Out-String | Add-Content $LogFile
                 Write-Host "`nRoot Hints turned off DNS Server $DNSServer" -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Root Hints turned off DNS Server $DNSServer" | Add-Content $LogFile
   
            }
        }else{

            #dnscmd /config /isSlave 1 # For Remote Server: dnscmd RemoteServerName /config /isSlave 1
            $cmd = "dnscmd /config /isSlave 1"
            Invoke-Expression $cmd | Out-String | Add-Content $LogFile
            Write-Host "`nRoot Hints turned off Local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Root Hints turned off Local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
        }
    }
}

#endregion

#region "Get DNS Statistics"

if($GetDnsStats -eq $true)
{

   $CSVToProcess = $CSVFile

   if($CSVToProcess -ne "")
   {
   
        Write-Host ""
        Write-Host "`nProcessing CSV file $CSVToProcess.... Importing and processing DNS Statistics" -ForegroundColor Green
        Write-Host ""
        Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing and processing DNS Statistics" | Add-Content $LogFile

        Import-Csv $CSVToProcess | ForEach-Object {

            $DNSServer ="$($_.DNSServer)" # # DNS Server Name

            try{
               
                Write-Host "`nCollecting DNS Statistics from $DNSServer" -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> Collecting DNS Statistics from $DNSServer" | Add-Content $LogFile

                #region "Advanced DNS Statistics from DNS Servers"
                if(!([string]::IsNullOrEmpty($DnsStatType)))
                {
                    #DNS --> Types of Stats Collected: "Time","Master","Secondary", "Ds", "Dbase", "Memory", "PacketMemory", "NbStatMem", "Records"
                    Switch ($DnsStatType)
                    {
                      Time{
                            Write-Host "`nCollecting DNS Time Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Time Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00000001"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }
                    
                     Master{
                            Write-Host "`nCollecting DNS Master Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Master Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00000010"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    Secondary{
                            Write-Host "`nCollecting DNS Secondary Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Secondary Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00000020"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                   
                    Ds{
                            Write-Host "`nCollecting DNS DS Integration Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS DS Integration Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00000400"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    Dbase{
                            Write-Host "`nCollecting DNS Database Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Database Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00040000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    Memory{
                            Write-Host "`nCollecting DNS Memory Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Memory Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00010000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    PacketMemory{
                            Write-Host "`nCollecting DNS Dbase Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Dbase Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00100000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    NbStatMem{
                            Write-Host "`nCollecting DNS NbStatMem Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS NbStatMem Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00200000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                  Records{
                            Write-Host "`nCollecting DNS Record Statistics from $DNSServer" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Record Statistics from $DNSServer" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd $DNSServer /statistics 00080000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }               

                    }

                }else{

                    dnscmd $DNSServer /statistics | Out-String | Add-Content $LogFile

                }
                #endregion

                Write-Host "`nDNS Statistics from $DNSServer has been collected successfully. Check $LogFile for statistics." -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> DNS Statistics from $DNSServer has been collected successfully.`n" | Add-Content $LogFile


            }
            catch [Exception]
            {
                Write-Host "`nUnable to collect DNS statistics from $DNSServer" -ForegroundColor Red
                Write-Host ""
                Write-Output "`n$CurrentDate --> Unable to collect DNS statistics from $DNSServer" | Add-Content $LogFile

            }
        }


   }
   else{

            try{ #Collecting Statistics from Local DNS Server
               
                Write-Host "`nCollecting DNS Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> Collecting DNS Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile

                #region "Advanced DNS Statistics from Local DNS Server"

                if(!([string]::IsNullOrEmpty($DnsStatType)))
                {
                    #DNS --> Types of Stats Collected: "Time","Master","Secondary", "Ds", "Dbase", "Memory", "PacketMemory", "NbStatMem", "Records"
                    Switch ($DnsStatType)
                    {
                      Time{
                            Write-Host "`nCollecting DNS Time Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Time Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00000001"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }  

                     Master{
                            Write-Host "`nCollecting DNS Master Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Master Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00000010"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    Secondary{
                            Write-Host "`nCollecting DNS Secondary Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Secondary Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00000020"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                   
                    Ds{
                            Write-Host "`nCollecting DNS DS Integration Statistics from from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS DS Integration Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00000400"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    Dbase{
                            Write-Host "`nCollecting DNS Database Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Database Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00040000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    Memory{
                            Write-Host "`nCollecting DNS Memory Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Memory Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00010000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    PacketMemory{
                            Write-Host "`nCollecting DNS Dbase Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Dbase Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00100000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                    NbStatMem{
                            Write-Host "`nCollecting DNS NbStatMem Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS NbStatMem Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00200000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }

                  Records{
                            Write-Host "`nCollecting DNS Record Statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                            Write-Host ""
                            Write-Output "`n$CurrentDate --> Collecting DNS Record Statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
                            $cmdSatsCommand = "dnscmd /statistics 00080000"
                            Invoke-Expression -Command $cmdSatsCommand
                            Invoke-Expression $cmdSatsCommand | Out-String | Add-Content $LogFile
                     
                      }               

                    }

                }else{

                    dnscmd /statistics | Out-String | Add-Content $LogFile
                }

                #endregion

                Write-Host "`nDNS Statistics from local DNS Server $env:COMPUTERNAME has been collected successfully. Check $LogFile for statistics." -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> DNS Statistics from local DNS Server $env:COMPUTERNAME has been collected successfully." | Add-Content $LogFile


            }
            catch [Exception]
            {
                Write-Host "`nUnable to collect DNS statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Red
                Write-Host ""
                Write-Output "`n$CurrentDate --> Unable to collect DNS statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile

            }
   }


}

#endregion

#region "Get DNS Information"

if($GetDnsInfo -eq $true)
{

    $CSVToProcess = $CSVFile

   if($CSVToProcess -ne "")
   {
   
        Write-Host ""
        Write-Host "`nProcessing CSV file $CSVToProcess.... Importing and collecting DNS Information" -ForegroundColor Green
        Write-Host ""
        Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing and collecting DNS Information" | Add-Content $LogFile

        Import-Csv $CSVToProcess | ForEach-Object {

            $DNSServer ="$($_.DNSServer)" # # DNS Server Name

            try{
               
                Write-Host "`nCollecting DNS Information from $DNSServer" -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> Collecting DNS Information from $DNSServer" | Add-Content $LogFile

                dnscmd $DNSServer /info | Out-String | Add-Content $LogFile

                Write-Host "`nDNS Information from $DNSServer has been collected successfully. Check $LogFile for Information." -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> DNS Statistics from $DNSServer has been collected successfully.`n" | Add-Content $LogFile


            }
            catch [Exception]
            {
                Write-Host "`nUnable to Collect DNS Information from $DNSServer" -ForegroundColor Red
                Write-Host ""
                Write-Output "`n$CurrentDate --> Unable to Collect DNS Information from $DNSServer" | Add-Content $LogFile

            }
        }


   }
   else{

            try{ #Collecting Information from Local DNS Server
               
                Write-Host "`nCollecting DNS Information from local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> Collecting DNS Information from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile

                dnscmd /info | Out-String | Add-Content $LogFile

                Write-Host "`nDNS Information from local DNS Server $env:COMPUTERNAME has been collected successfully. Check $LogFile for Information." -ForegroundColor Green
                Write-Host ""
                Write-Output "`n$CurrentDate --> DNS Information from local DNS Server $env:COMPUTERNAME has been collected successfully." | Add-Content $LogFile


            }
            catch [Exception]
            {
                Write-Host "`nUnable to collect DNS statistics from local DNS Server $env:COMPUTERNAME" -ForegroundColor Red
                Write-Host ""
                Write-Output "`n$CurrentDate --> Unable to collect DNS statistics from local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile

            }
   }

}


#endregion

#region Restore DNS"

if($RestoreDNS -eq $true)
{
    #region "Set Restore Variables"

    $DNSSERVER=gc env:computername
    $ProcessingStartTime = Get-Date
    $DnsRestoreFolder = "C:\" + $DNSSERVER + "_DNSBackup\"
    $DnsRestoreCSVFile = $env:COMPUTERNAME + "_DNSSettingsBackup.csv"
    $DnsRestorePath = $DnsRestoreFolder + $DnsRestoreCSVFile

    $BkfFolder=”c:\windows\system32\dns\backup\”
    #$BkfFolder=$DnsRestoreFolder

    $AllDnsZons = dnscmd /EnumZones
    $ZoneList = $AllDnsZons | Out-String

    $ZoneExists = ""

    #endregion

    Write-Host "`nPlease make sure that the DNS management console is installed first`n" -ForegroundColor Green
    $dnsInput = Read-Host "`nIs the DNS Management consoled installed? (Y/N)"

    while("y","Y","n","N" -notcontains $dnsInput) #We are only accepting Y/N anything else is ignored
    {
        $dnsInput = Read-Host "`nIs the DNS Management consoled installed? (Y/N)" # Y/N was not inputed. Keep asing until Y/N has been entered
    }


    #region "Test if DNS Management Console exists"

    if(($dnsInput -eq "y") -or ($dnsInput -eq "Y"))
    {
        #Lets test and see if the DNS Management Console actually exits

       

        $DnsConsoleExists = $false

        $SystemPath = $env:SystemRoot + "\System32\"
        $DnsConsolePath = $SystemPath + "dnsmgmt.msc"

        if(Test-Path $DnsConsolePath )
        {
            $DnsConsoleExists = $true
            Write-Host "`nDNS Management Console Exits.... Continuing with script." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> DNS Management Console Exits.... Continuing with script." | Add-Content $LogFile

        }else{

            $DnsConsoleExists = $false
            Write-Host "`nDNS Management Console does not exits.... Exiting Script." -ForegroundColor Cyan
            Write-Output "`n$CurrentDate --> DNS Management Console does not exits.... Exiting Script." | Add-Content $LogFile
            Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
            Exit
        }

        #endregion

        if($DnsConsoleExists -eq $true)
        {
            Write-Host "`nChecking if backup folder $DnsRestoreFolder exists....." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Checking if backup folder $DnsRestoreFolder exists....." | Add-Content $LogFile

            If ((Test-Path $DnsRestoreFolder))
            {
                 Write-Host "`nFolder $DnsRestoreFolder does exists." -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Folder $DnsRestoreFolder does exists." | Add-Content $LogFile
                                
                 Write-Host "`nProceeding with DNS Restore.... " -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Proceeding with DNS Restore...." | Add-Content $LogFile

                              
           }else{

                 Write-Host "`nFolder $DnsRestoreFolder does not exists. Unable to proceed any further...." -ForegroundColor Cyan
                 Write-Output "`n$CurrentDate --> Folder $DnsRestoreFolder does not exists. Unable to proceed any further...." | Add-Content $LogFile
               
                 Write-Host "`nExiting Script.... " -ForegroundColor Cyan
                 Write-Output "`n$CurrentDate --> Exiting Script...." | Add-Content $LogFile
                 Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
                 Exit

           }

        }
      }else{
       
         Write-Host "`nExiting Script.... " -ForegroundColor Cyan
         Write-Output "`n$CurrentDate --> Exiting Script...." | Add-Content $LogFile
         Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
         Exit
      }

      $Zone=import-csv $DnsRestorePath
      $Zone | foreach {

        try{

            $ZoneName = $_.name
            $path="Backup\" + $ZoneName + ".bak"
            $IP=$_.MasterServers
            $Update=$_.AllowUpdate

            #Check if Zone Exists

            $zoneExistsCommand = "dnscmd /ZoneInfo " + $ZoneName

            $result = Invoke-Expression -Command $zoneExistsCommand

            $ZoneExists = $result | Out-String

            #—– Checking if AD Integrated or Not ——-#
            if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST"))
            {

                if ($_.DsIntegrated -eq $True)
                {
             
                    Switch ($_.ZoneType)
                    {
                        1 {
                              #—– Need to Create Zone As Primary to get all records imported ——-#
                              $cmd0=”dnscmd {0} /ZoneAdd {1} /primary /file {2} /load” -f $DNSSERVER,$ZoneName,$path
                              Write-Host "`nExecuting DNSCMD ZoneAdd command $cmd0" -ForegroundColor Green
                              Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $cmd0" | Add-Content $LogFile
                              Write-Host "`nRestoring Zone $ZoneName" -ForegroundColor Green
                              Write-Output "`n$CurrentDate --> Restoring Zone $ZoneName" | Add-Content $LogFile
                              Invoke-Expression $cmd0 | Out-String | Add-Content $LogFile
                         
                              $cmd1=”dnscmd {0} /ZoneResetType {1} /dsprimary” -f $DNSSERVER,$ZoneName
 
                         }
                         3 {
                         
                              $cmd1=”dnscmd {0} /ZoneAdd {1} /dsstub {2} /load” -f $DNSSERVER,$ZoneName,$IP
                         
                              Write-Host "`nExecuting DNSCMD ZoneAdd command $cmd1" -ForegroundColor Green
                              Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $cmd1" | Add-Content $LogFile
                              Write-Host "`nRestoring Zone $ZoneName" -ForegroundColor Green
                              Write-Output "`n$CurrentDate --> Restoring Zone $ZoneName" | Add-Content $LogFile  
                           }
                         4 {
                         
                              $cmd1=”dnscmd {0} /ZoneAdd {1} /dsforwarder {2} /load” -f $DNSSERVER,$ZoneName,$IP
                       
                              Write-Host "`nExecuting DNSCMD ZoneAdd command $cmd1" -ForegroundColor Green
                              Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $cmd1" | Add-Content $LogFile
                              Write-Host "`nRestoring Zone $ZoneName" -ForegroundColor Green
                              Write-Output "`n$CurrentDate --> Restoring Zone $ZoneName" | Add-Content $LogFile 
                            }
                    }
           
                }else{

                    Switch ($_.ZoneType)
                      {
                          1 {
                                $cmd1=”dnscmd {0} /ZoneAdd {1} /primary /file {2} /load” -f $DNSSERVER,$ZoneName,$path
                                Write-Host "`nExecuting DNSCMD ZoneAdd command $cmd1" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $cmd1" | Add-Content $LogFile
                                Write-Host "`nRestoring Zone $ZoneName" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Restoring Zone $ZoneName" | Add-Content $LogFile

                            }
                          2 {
                                $cmd1=”dnscmd {0} /ZoneAdd {1} /secondary {2}” -f $DNSSERVER,$ZoneName,$IP
                           
                                Write-Host "`nExecuting DNSCMD ZoneAdd command $cmd1" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $cmd1" | Add-Content $LogFile
                                Write-Host "`nRestoring Zone $ZoneName" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Restoring Zone $ZoneName" | Add-Content $LogFile
                        
                             }
                          3 {
                                $cmd1=”dnscmd {0} /ZoneAdd {1} /stub {2}” -f $DNSSERVER,$ZoneName,$IP
                           
                                Write-Host "`nExecuting DNSCMD ZoneAdd command $cmd1" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $cmd1" | Add-Content $LogFile
                                Write-Host "`nRestoring Zone $ZoneName" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Restoring Zone $ZoneName" | Add-Content $LogFile   
                            }
                          4 {
                     
                                $cmd1=”dnscmd {0} /ZoneAdd {1} /forwarder {2}” -f $DNSSERVER,$ZoneName,$IP
                                Write-Host "`nExecuting DNSCMD ZoneAdd command $cmd1" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $cmd1" | Add-Content $LogFile
                                Write-Host "`nRestoring Zone $ZoneName" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Restoring Zone $ZoneName" | Add-Content $LogFile
                           
                            }
                      }

                }
         
 
              #Restore DNS Zones 
              Invoke-Expression $cmd1 | Out-String | Add-Content $LogFile

              Switch ($_.AllowUpdate)
               {
                  #No Update
                  0 {$cmd2=”dnscmd /Config {0} /allowupdate {1}” -f $ZoneName,$Update}
                  #Secure and non secure
                  1 {$cmd2=”dnscmd /Config {0} /allowupdate {1}” -f $ZoneName,$Update}
                  #Only Secure Updates
                  2 {$cmd2=”dnscmd /Config {0} /allowupdate {1}” -f $ZoneName,$Update}
 
               }

               #Reset DNS Update Settings
                Write-Host "`nExecuting DNSCMD ZoneUpdate command $cmd2" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneUpdate command $cmd2" | Add-Content $LogFile
                Write-Host "`nUpdating Zone $ZoneName" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Updating Zone $ZoneName" | Add-Content $LogFile
                Invoke-Expression $cmd2 | Out-String | Add-Content $LogFile
        }


        }
        catch [Exception]
        {
            Write-Host "`nError Restoring Zone $ZoneName" -ForegroundColor Red
            Write-Output "`n$CurrentDate --> Error Restoring Zone $ZoneName" | Add-Content $LogFile

        }


      }


        $ProcessingEndTime = Get-Date
        $duration = "{0:n2}" -f ($ProcessingEndTime.Subtract($ProcessingStartTime).TotalSeconds)
        $durationMinutes = [decimal]::Round($duration / 60)

        Write-Host "`n--------------------------------------------------------------------------------------------------------------------" -ForegroundColor Cyan
        Write-Host "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
        Write-Host "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
        Write-Host "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" -ForegroundColor Cyan
        Write-Host "`n--------------------------------------------------------------------------------------------------------------------`n" -ForegroundColor Cyan


        Write-Output "`n--------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" | Add-Content $LogFile
        Write-Output "`n--------------------------------------------------------------------------------------------------------------------`n" | Add-Content $LogFile


}

#endregion

#region "Backup DNS"

if($BackUpDNS -eq $true) #Backup of DNS
{

    <#
   
    NOTE: The backup performed is currently only supported on the local dns server. Assuming that everything is Active Directory Integrated
    The script will backup all zones Primary, Reverse lookup zones.

    The zone backup will occur to the following path c:\windows\system32\dns\backup and then it will be copied to
    C:\ServerName_DNSBackup\

    #>

    #DNS Backup Folder

    #region "Set Backup Variables"

    $ProcessingStartTime = Get-Date
    $DnsBackupFolder = "C:\" + $env:COMPUTERNAME + "_DNSBackup\"
    $DnsBackupCSVFile = $env:COMPUTERNAME + "_DNSSettingsBackup.csv"
    $DnsBackUpPath = $DnsBackupFolder + $DnsBackupCSVFile

    $BkfFolder=”c:\windows\system32\dns\backup”

    #endregion
   
    Write-Host "`nPlease make sure that the DNS management console is installed first`n" -ForegroundColor Green
    $dnsInput = Read-Host "`nIs the DNS Management consoled installed? (Y/N)"

    while("y","Y","n","N" -notcontains $dnsInput) #We are only accepting Y/N anything else is ignored
    {
        $dnsInput = Read-Host "`nIs the DNS Management consoled installed? (Y/N)" # Y/N was not inputed. Keep asking until Y/N has been entered
    }
    #Write-Host "`nIs the DNS Management consoled installed? (Y/N)"
    #Read-Host $dnsInput  
   
    #region "Test if DNS Management Console exists"

    if(($dnsInput -eq "y") -or ($dnsInput -eq "Y"))
    {
        #Lets test and see if the DNS Management Console actually exits

       

        $DnsConsoleExists = $false

        $SystemPath = $env:SystemRoot + "\System32\"
        $DnsConsolePath = $SystemPath + "dnsmgmt.msc"

        if(Test-Path $DnsConsolePath )
        {
            $DnsConsoleExists = $true
            Write-Host "`nDNS Management Console Exits.... Continuing with script." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> DNS Management Console Exits.... Continuing with script." | Add-Content $LogFile

        }else{

            $DnsConsoleExists = $false
            Write-Host "`nDNS Management Console does not exits.... Exiting Script." -ForegroundColor Cyan
            Write-Output "`n$CurrentDate --> DNS Management Console does not exits.... Exiting Script." | Add-Content $LogFile
            Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
            Exit
        }

        #endregion

        if($DnsConsoleExists -eq $true)
        {
            Write-Host "`nChecking if backup folder $DnsBackupFolder exists....." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Checking if backup folder $DnsBackupFolder exists....." | Add-Content $LogFile

            If (!(Test-Path $DnsBackupFolder))
            {
                 Write-Host "`nFolder $DnsBackupFolder does not exists. Createing backup folder $DnsBackupFolder " -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Folder $DnsBackupFolder does not exists. Createing backup folder $DnsBackupFolder" | Add-Content $LogFile
               
                 new-item -type Directory -path $DnsBackupFolder #Create the DNS Backup folder

                 Write-Host "`nRemoving old backup data from backup folder $DnsBackupFolder if it exists.... " -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Removing old backup data from backup folder $DnsBackupFolder if it exists...." | Add-Content $LogFile

                 Write-Host "`nRemoving old DNS backup from folder C:\Windows\System32\dns\backup if it exists.... " -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Removing old DNS backup from folder C:\Windows\System32\dns\backup if it exists...." | Add-Content $LogFile


                 Remove-Item $DnsBackupFolder"\*" -Recurse

                 Remove-Item $BkfFolder"\*" -Recurse
              

            }else{

                 Write-Host "`nFolder $DnsBackupFolder does exists." -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Folder $DnsBackupFolder does exists." | Add-Content $LogFile

                 Write-Host "`nRemoving old backup data from backup folder $DnsBackupFolder if it exists.... " -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Removing old backup data from backup folder $DnsBackupFolder if it exists...." | Add-Content $LogFile

                 Write-Host "`nRemoving old DNS backup from folder C:\Windows\System32\dns\backup if it exists.... " -ForegroundColor Green
                 Write-Output "`n$CurrentDate --> Removing old DNS backup from folder C:\Windows\System32\dns\backup if it exists...." | Add-Content $LogFile


                 Remove-Item $DnsBackupFolder"\*" -Recurse
                
                 Remove-Item $BkfFolder"\*" -Recurse
     
            }
       
            Write-Host "`nStarting backup of DNS................." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Starting backup of DNS................." | Add-Content $LogFile

            Write-Host "`nConnecting to DNS Name Space using WMI" -ForegroundColor Green
            Write-Output "`n$CurrentDate --> Connecting to DNS Name Space using WMI" | Add-Content $LogFile

            $List = get-WmiObject -ComputerName $env:COMPUTERNAME -Namespace root\MicrosoftDNS -Class MicrosoftDNS_Zone #Backup local dns server at the moment

            #—-Export information into DNSSettingsBackup.csv file —#
            #– Line wrapped should be only one line –#
            $List | Select Name,ZoneType,AllowUpdate,@{Name=”MasterServers”;Expression={$_.MasterServers}}, DsIntegrated | Export-csv $DnsBackUpPath -NoTypeInformation

            Write-Host "`n*** NOTE: All DNS zone backups are located in C:\Windows\System32\dns\backup ***" -ForegroundColor Cyan
            Write-Output "`n$CurrentDate --> NOTE: All DNS zone backups are located in C:\Windows\System32\dns\backup" | Add-Content $LogFile

            #— Call Dnscmd.exe to export dns zones
            $List | foreach {
                try{
                    $ZoneName = $_.name
                    $path="Backup\" + $ZoneName + ".bak"
                    $dnsZonePath = $env:SystemRoot + "\System32\dns\" + $path
                    $cmd=”dnscmd {0} /ZoneExport {1} {2}” -f $env:COMPUTERNAME,$_.Name,$path
                    Write-Host "`nExecuting DNSCMD ZoneExport command $cmd" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneExport command $cmd" | Add-Content $LogFile
                    Write-Host "`nBacking up Zone $ZoneName" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Backing up Zone $ZoneName" | Add-Content $LogFile
                    #Invoke-Expression $cmd
                    Invoke-Expression $cmd | Out-String | Add-Content $LogFile
                    Write-Host "`nZone $ZoneName backed up successfully" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Zone $ZoneName backed up successfully" | Add-Content $LogFile
                    if(Test-Path $dnsZonePath) #Make sure the Zone has been exported out before copying it
                    {
                        $copyCommand = "xcopy $dnsZonePath $DnsBackupFolder /y"
                        Write-Host "`nExecuting copy command $copyCommand" -ForegroundColor Green
                        Write-Output "`n$CurrentDate --> Executing copy command $copyCommand" | Add-Content $LogFile
                        Invoke-Expression $copyCommand
                        Invoke-Expression $copyCommand | Out-String | Add-Content $LogFile
                        Write-Host "`nCopy of zone $ZoneName completed successfully." -ForegroundColor Green
                        Write-Output "`n$CurrentDate --> Copy of zone $ZoneName completed successfully." | Add-Content $LogFile
                    }
                }
                catch [Exception]
                {
                    Write-Host "`nError Exporting Zone $ZoneName" -ForegroundColor Red
                    Write-Output "`n$CurrentDate --> Error Exporting Zone $ZoneName" | Add-Content $LogFile

                }

            }

            Write-Host "`nDNS Backup for $env:COMPUTERNAME is completed successfully." -ForegroundColor Green
            Write-Output "`n$CurrentDate --> DNS Backup for $env:COMPUTERNAME is completed successfully." | Add-Content $LogFile
        }

        $ProcessingEndTime = Get-Date
        $duration = "{0:n2}" -f ($ProcessingEndTime.Subtract($ProcessingStartTime).TotalSeconds)
        $durationMinutes = [decimal]::Round($duration / 60)

        Write-Host "`n--------------------------------------------------------------------------------------------------------------------" -ForegroundColor Cyan
        Write-Host "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
        Write-Host "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
        Write-Host "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" -ForegroundColor Cyan
        Write-Host "`n--------------------------------------------------------------------------------------------------------------------`n" -ForegroundColor Cyan


        Write-Output "`n--------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
        Write-Output "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" | Add-Content $LogFile
        Write-Output "`n--------------------------------------------------------------------------------------------------------------------`n" | Add-Content $LogFile


    }else{
       
        Write-Host "`nExiting Script...." -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Exiting Script...." | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit #Leave script
    }

   

}

#endregion

#region "Create a New Forward-Lookup Zone"

if($NewForwardZone -eq $true)
{
    $CSVToProcess = $ZoneCSVFile #Set Zone CSV File

    if($CSVToProcess -ne "")
    {
        Write-Host ""
        Write-Host "Processing CSV file $CSVToProcess.... Importing Forward Lookup Zone Information" -ForegroundColor Green
        Write-Host ""
        Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing Forward Lookup Zone Information" | Add-Content $LogFile

        Import-Csv $CSVToProcess | ForEach-Object {

            try{
                $ForwardZoneName ="$($_.ZoneName)" # Forward-Lookup Zone Name

                $zoneCommand ="dnscmd /ZoneAdd $ForwardZoneName /DSPrimary" #Add and Active Directory Integrated Zone Only
                Write-Host "`nExecuting DNSCMD ZoneAdd command $zoneCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $zoneCommand" | Add-Content $LogFile
                #Invoke-Expression $zoneCommand
                Invoke-Expression $zoneCommand | Out-String | Add-Content $LogFile
                Write-Host "`nForward Lookup Zone $ForwardZoneName has been created successfully" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Forward Lookup Zone $ForwardZoneName has been created successfully" | Add-Content $LogFile
                if($AllowDynamicUpdates -eq $true) #Secure Updates Only
                {
                    <#

                    For dynamic updates the following decimal values can be used
                   
                    0 --> No Dynamic updates
                    1 --> Allow both Secure and non-Secure Dynamic Updates
                    2--> Allow only Secure Dynamic Updates (Default setting for script)

                    #>

                    $zoneDynamicUpdate ="dnscmd /Config $ForwardZoneName /AllowUpdate 2" #Enable Dynamic Updates on Zones
                    Write-Host "`nExecuting DNSCMD DynamicUpdate command $zoneDynamicUpdate" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing DNSCMD DynamicUpdate command $zoneDynamicUpdate" | Add-Content $LogFile
        
                    #Invoke-Expression $zoneDynamicUpdate
                    Invoke-Expression $zoneDynamicUpdate | Out-String | Add-Content $LogFile
                    Write-Host "`nZone $ForwardZoneName has been configured for DynamicUpdates" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Zone $ForwardZoneName has been configured for DynamicUpdates" | Add-Content $LogFile
           
                }
            }
            catch [Exception]
            {
                Write-Host "`nError Add new Forward Lookup Zone $ForwardZoneName failed" -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Error Add new Forward Lookup Zone $ForwardZoneName failed" | Add-Content $LogFile

            }
                 
       }

           Write-Host "`nAll Forward Lookup Zones have been added into DNS successfully." -ForegroundColor Cyan
           Write-Output "`n$CurrentDate --> All Forward Lookup Zones have been added into DNS successfully." | Add-Content $LogFile


    }

}

#endregion

#region "Create a New Reverse-Lookup Zone"

if($NewReverseZone -eq $true)
{

    $CSVToProcess = $ZoneCSVFile #Set Zone CSV File

    if($CSVToProcess -ne "")
    {

        Write-Host ""
        Write-Host "Processing CSV file $CSVToProcess.... Importing Reverse Lookup Zone Information" -ForegroundColor Green
        Write-Host ""
        Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing Reverse Lookup Zone Information" | Add-Content $LogFile

        Import-Csv $CSVToProcess | ForEach-Object {
            try{

                $ReverseZoneIP ="$($_.ZoneName)" # Reverse-Lookup Zone Name
                $addRvs = $ReverseZoneIP -split "\."
                $zoneConstant = ".in-addr.arpa"

                if($addRvs.Length -eq 4) #Eg: 192.168.0.0
                {
                   $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                }

                if($addRvs.Length -eq 3)#Eg: 192.168.0
                {
                   $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                }

                if(($addRvs.Length -eq 2))#Eg: 192.168
                {

                    $rZone = "$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                }

                if(($addRvs.Length -eq 1))
                {

                    $rZone = "$($addRvs[0]).in-addr.arpa"
                }

                $zoneCommand ="dnscmd /ZoneAdd $rZone /DSPrimary" #Add and Active Directory Integrated Zone Only
                Write-Host "`nExecuting DNSCMD ZoneAdd command $zoneCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $zoneCommand" | Add-Content $LogFile
                #Invoke-Expression $zoneCommand
                Invoke-Expression $zoneCommand | Out-String | Add-Content $LogFile
                Write-Host "`nReverse Lookup Zone $rZone has been created successfully" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Reverse Lookup Zone $rZone has been created successfully" | Add-Content $LogFile
                if($AllowDynamicUpdates -eq $true) #Secure Updates Only
                {
                    <#

                    For dynamic updates the following decimal values can be used
                   
                    0 --> No Dynamic updates
                    1 --> Allow both Secure and non-Secure Dynamic Updates
                    2--> Allow only Secure Dynamic Updates (Default setting for script)

                    #>

                    $zoneDynamicUpdate ="dnscmd /Config $rZone /AllowUpdate 2" #Enable Dynamic Updates on Zones
                    Write-Host "`nExecuting DNSCMD DynamicUpdate command $zoneDynamicUpdate" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing DNSCMD DynamicUpdate command $zoneDynamicUpdate" | Add-Content $LogFile
        
                    #Invoke-Expression $zoneDynamicUpdate
                    Invoke-Expression $zoneDynamicUpdate | Out-String | Add-Content $LogFile
                    Write-Host "`nZone $ForwardZoneName has been configured for DynamicUpdates" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Zone $ForwardZoneName has been configured for DynamicUpdates" | Add-Content $LogFile
           
                }

               

            }
            catch [Exception]
            {

                Write-Host "`nError Add new Reverse Lookup Zone $ForwardZoneName failed" -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Error Add new Forward Lookup Zone $ForwardZoneName failed" | Add-Content $LogFile

            }

        }

                       
            Write-Host "`nAll Reverse Lookup Zones have been added into DNS successfully." -ForegroundColor Cyan
            Write-Output "`n$CurrentDate --> All Reverse Lookup Zones have been added into DNS successfully." | Add-Content $LogFile

    }

}

#endregion

#region "Delete a DNS Zone or Import CSV to Delete multiple Zones"

if($DeleteZone -eq $true)
{
    if($DeleteZoneNameOrCSV -ne "")
    {
        $ProcessingStartTime = Get-Date

        $ZoneFile = $DeleteZoneNameOrCSV #Set Zone Name/ CSV File

        #Check if an extension exits

        $FileExt = [System.IO.Path]::GetExtension($ZoneFile) #Get Extension of File

        if($FileExt -eq ".csv") #Check extension, if its a CSV
        {
           
            #File extension is .csv

            <#

                ZoneDelete syntax:

                DnsCmd <ServerName> /ZoneDelete <ZoneName> /[DsDel] [/f]
                   
                DsDel --> Delete zone from DS (Active Directory Integrated Deletion)
                f --> Execute without asking for confirmation
                Default --> Delete zone from DNS Server, but NOT from DS

            #>

            Write-Host ""
            Write-Host "Processing CSV file $ZoneFile.... Importing DNS Zone Information for deletion" -ForegroundColor Green
            Write-Host ""
            Write-Output "`n$CurrentDate --> Processing CSV file $ZoneFile.... Importing DNS Zone Information for deletion" | Add-Content $LogFile

            Import-Csv $ZoneFile | ForEach-Object {

                try{
                   
                    if($GetZoneType -eq "Forward")
                    {
                        $ZoneToDelete ="$($_.ZoneName)" # Forward-Lookup Zone Name

                        $zoneCommandDel ="dnscmd /ZoneDelete $ZoneToDelete /DsDel /f" #Delete and Active Directory Integrated Zone.
                        Write-Host "`nExecuting DNSCMD ZoneDelete command $zoneCommandDel" -ForegroundColor Green
                        Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneDelete command $zoneCommandDel" | Add-Content $LogFile
                        #Invoke-Expression $zoneCommandDel
                        Invoke-Expression $zoneCommandDel | Out-String | Add-Content $LogFile
                        Write-Host "`nZone $ZoneToDelete has been deleted successfully" -ForegroundColor Green
                        Write-Output "`n$CurrentDate --> Zone $ZoneToDelete has been deleted successfully" | Add-Content $LogFile
                    }

                    if($GetZoneType -eq "Reverse")
                    {

                        $ReverseZoneIP ="$($_.ZoneName)" # Reverse-Lookup Zone Name
                        $addRvs = $ReverseZoneIP -split "\."
                        $zoneConstant = ".in-addr.arpa"

                        #$rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"

                        if($addRvs.Length -eq 4) #Eg: 192.168.0.0
                        {
                            $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                        }

                        if($addRvs.Length -eq 3)#Eg: 192.168.0
                        {
                            $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                        }

                        if(($addRvs.Length -eq 2))#Eg: 192.168
                        {

                            $rZone = "$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                        }

                        if(($addRvs.Length -eq 1))
                        {

                            $rZone = "$($addRvs[0]).in-addr.arpa"
                        }

                        $zoneCommandDel ="dnscmd /ZoneDelete $rZone /DsDel /f" #Delete and Active Directory Integrated Zone.
                        Write-Host "`nExecuting DNSCMD ZoneDelete command $zoneCommandDel" -ForegroundColor Green
                        Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneDelete command $zoneCommandDel" | Add-Content $LogFile
                        #Invoke-Expression $zoneCommandDel
                        Invoke-Expression $zoneCommandDel | Out-String | Add-Content $LogFile
                        Write-Host "`nZone $rZone has been deleted successfully" -ForegroundColor Green
                        Write-Output "`n$CurrentDate --> Zone $rZone has been deleted successfully" | Add-Content $LogFile
                    }

                }
                catch [Exception]
                {
                   
                    Write-Host "`nError Deleteing Zone $ZoneToDelete" -ForegroundColor Red
                    Write-Output "`n$CurrentDate --> Error Deleteing Zone $ZoneToDelete" | Add-Content $LogFile

   

                }
              
            }
       

        }
        else{ #Where deleting just a single zone

            try{
               
                <#

                    ZoneDelete syntax:

                    DnsCmd <ServerName> /ZoneDelete <ZoneName> /[DsDel] [/f]
                   
                    DsDel --> Delete zone from DS (Active Directory Integrated Deletion)
                    f --> Execute without asking for confirmation
                    Default --> Delete zone from DNS Server, but NOT from DS

                #>

                 if($GetZoneType -eq "Forward")
                 {
                     $ZoneToDelete = $DeleteZoneNameOrCSV #This is just a single zone

                     $zoneCommandDel ="dnscmd /ZoneDelete $ZoneToDelete /DsDel /f" #Add and Active Directory Integrated Zone Only
                     Write-Host "`nExecuting DNSCMD ZoneDelete command $zoneCommandDel" -ForegroundColor Green
                     Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneDelete command $zoneCommandDel" | Add-Content $LogFile
                     #Invoke-Expression $zoneCommandDel
                     Invoke-Expression $zoneCommandDel | Out-String | Add-Content $LogFile
                     Write-Host "`nZone $ZoneToDelete has been deleted successfully" -ForegroundColor Green
                     Write-Output "`n$CurrentDate --> Zone $ZoneToDelete has been deleted successfully" | Add-Content $LogFile
                 }

                 if($GetZoneType -eq "Reverse")
                 {

                    $ReverseZoneIP =$DeleteZoneNameOrCSV # Reverse-Lookup Zone Name
                    $addRvs = $ReverseZoneIP -split "\."
                    $zoneConstant = ".in-addr.arpa"

                    #$rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"

                    if($addRvs.Length -eq 4) #Eg: 192.168.0.0
                      {
                            $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                      }

                    if($addRvs.Length -eq 3)#Eg: 192.168.0
                      {
                            $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                      }

                    if(($addRvs.Length -eq 2))#Eg: 192.168
                      {

                            $rZone = "$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                      }

                    if(($addRvs.Length -eq 1))
                      {

                            $rZone = "$($addRvs[0]).in-addr.arpa"
                      }


                    $zoneCommandDel ="dnscmd /ZoneDelete $rZone /DsDel /f" #Delete and Active Directory Integrated Zone.
                    Write-Host "`nExecuting DNSCMD ZoneDelete command $zoneCommandDel" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneDelete command $zoneCommandDel" | Add-Content $LogFile
                    #Invoke-Expression $zoneCommandDel
                    Invoke-Expression $zoneCommandDel | Out-String | Add-Content $LogFile
                    Write-Host "`nZone $rZone has been deleted successfully" -ForegroundColor Green
                    Write-Output "`n$CurrentDate --> Zone $rZone has been deleted successfully" | Add-Content $LogFile
                 }

                }
                catch [Exception]
                {
                   
                  Write-Host "`nError Deleteing Zone $ZoneToDelete" -ForegroundColor Red
                  Write-Output "`n$CurrentDate --> Error Deleteing Zone $ZoneToDelete" | Add-Content $LogFile

   

                }
            }
    }

    $ProcessingEndTime = Get-Date
    $duration = "{0:n2}" -f ($ProcessingEndTime.Subtract($ProcessingStartTime).TotalSeconds)
    $durationMinutes = [decimal]::Round($duration / 60)

    Write-Host "`n--------------------------------------------------------------------------------------------------------------------" -ForegroundColor Cyan
    Write-Host "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
    Write-Host "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
    Write-Host "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" -ForegroundColor Cyan
    Write-Host "`n--------------------------------------------------------------------------------------------------------------------`n" -ForegroundColor Cyan


    Write-Output "`n--------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
    Write-Output "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
    Write-Output "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
    Write-Output "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" | Add-Content $LogFile
    Write-Output "`n--------------------------------------------------------------------------------------------------------------------`n" | Add-Content $LogFile


}

#endregion

#region "Enumerate Zones"

if($GetAllZones -eq $true)
{
    try{
        if($GetZoneType -eq "Forward") #Enumerate All Forward Zones
        {
            if($AutoCreatedZones -eq $true) #Get only AutoCreated Forward Zones
            {
           
                $GetForwardZonesCommand ="dnscmd /EnumZones /Auto-Created /$GetZoneType" #Enumerate Forward Auto-Created zones as well.
                Write-Host "`nExecuting DNSCMD Zone Enumeration (Auto-Created) command $GetForwardZonesCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD Zone Enumeration (Auto-Created) command $GetForwardZonesCommand" | Add-Content $LogFile
                Invoke-Expression $GetForwardZonesCommand
                Invoke-Expression $GetForwardZonesCommand | Out-String | Add-Content $LogFile
                Write-Host "`nDNS Forward Zones (Auto-Created) Enumerated successfully." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> DNS Forward Zones (Auto-Created) Enumerated successfully." | Add-Content $LogFile


            }else{
               
                $GetForwardZonesCommand ="dnscmd /EnumZones /$GetZoneType" #Enumerate Forward zones.
                Write-Host "`nExecuting DNSCMD Zone Enumeration command $GetForwardZonesCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD Zone Enumeration command $GetForwardZonesCommand" | Add-Content $LogFile
                Invoke-Expression $GetForwardZonesCommand
                Invoke-Expression $GetForwardZonesCommand | Out-String | Add-Content $LogFile
                Write-Host "`nDNS Forward Zones Enumerated successfully." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> DNS Forward Zones Enumerated successfully." | Add-Content $LogFile

            }

        }
        elseif ($GetZoneType -eq "Reverse")
        {
            if($AutoCreatedZones -eq $true)
            {
                $GetReverseZonesCommand ="dnscmd /EnumZones /Auto-Created /$GetZoneType" #Enumerate Reverse Auto-Created zones as well.
                Write-Host "`nExecuting DNSCMD Zone Enumeration (Auto-Created) command $GetReverseZonesCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD Zone Enumeration (Auto-Created) command $GetReverseZonesCommand" | Add-Content $LogFile
                Invoke-Expression $GetReverseZonesCommand
                Invoke-Expression $GetReverseZonesCommand | Out-String | Add-Content $LogFile
                Write-Host "`nDNS Reverse Zones (Auto-Created) Enumerated successfully." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> DNS Reverse Zones (Auto-Created) Enumerated successfully." | Add-Content $LogFile

            }else{

                $GetReverseZonesCommand ="dnscmd /EnumZones /$GetZoneType" #Enumerate Reverse zones.
                Write-Host "`nExecuting DNSCMD Zone Enumeration command $GetReverseZonesCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD Zone Enumeration command $GetReverseZonesCommand" | Add-Content $LogFile
                Invoke-Expression $GetReverseZonesCommand
                Invoke-Expression $GetReverseZonesCommand | Out-String | Add-Content $LogFile
                Write-Host "`nDNS Reverse Zones Enumerated successfully." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> DNS Reverse Zones Enumerated successfully." | Add-Content $LogFile

            }

        }else{

            if($AutoCreatedZones -eq $true)
            {
               
                $GetAllZonesCommand ="dnscmd /EnumZones /Auto-Created" #Enumerate All Zones including Auto-Created zones as well.
                Write-Host "`nExecuting DNSCMD Zone Enumeration (Auto-Created) command $GetAllZonesCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD Zone Enumeration (Auto-Created) command $GetAllZonesCommand" | Add-Content $LogFile
                Invoke-Expression $GetAllZonesCommand
                Invoke-Expression $GetAllZonesCommand | Out-String | Add-Content $LogFile
                Write-Host "`nDNS Server All (Auto-Created) Zones Enumerated successfully." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> DNS Server All (Auto-Created) Zones Enumerated successfully." | Add-Content $LogFile

            }else{
               
                $GetAllZonesCommand ="dnscmd /EnumZones" #Enumerate All Zones.
                Write-Host "`nExecuting DNSCMD Zone Enumeration command $GetAllZonesCommand" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Executing DNSCMD Zone Enumeration command $GetAllZonesCommand" | Add-Content $LogFile
                Invoke-Expression $GetAllZonesCommand
                Invoke-Expression $GetAllZonesCommand | Out-String | Add-Content $LogFile
                Write-Host "`nDNS Server All Zones Enumerated successfully." -ForegroundColor Green
                Write-Output "`n$CurrentDate --> DNS Server All Zones Enumerated successfully." | Add-Content $LogFile
               
            }

        }

    }
    catch [Exception]
    {

        Write-Host "`nError Enumerating DNS Zones" -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Error Enumerating DNS Zones" | Add-Content $LogFile

    }

}

#endregion

#region "Import DNS Zone Records"

if($PopulateDNSRecords -eq $true)
{
   $ProcessingStartTime = Get-Date

   $RevserseRecordCount = 0
   $ARecordCount = 0
   $MXRecordCount = 0
  
   $RecordsCSVFiles = $RecordsCSVPath + "\*.csv"
  
   $AllCSVFiles = Get-ChildItem -Path $RecordsCSVFiles

   ForEach ($RecordCSVFile in $AllCSVFiles)
   {
  
       $CSVToProcess = $RecordCSVFile

        Write-Host ""
        Write-Host "Processing CSV file $CSVToProcess.... Importing DNS Records...." -ForegroundColor Green
        Write-Host ""
        Write-Output "`n$CurrentDate --> Processing CSV file $CSVToProcess.... Importing DNS Records...." | Add-Content $LogFile

        Import-Csv $CSVToProcess | ForEach-Object {

            try{

                $ZoneName ="$($_.Name)" # Zone name of  DNS Conditional Forwarder
                $RecordType =$_.Type   # Zone Record Type
                $RecordData =$_.Data   # Zone Record Data (ServerName/Device name)

               
                if(!($ZoneName.Contains("(same as parent folder)")) -and !($ZoneName.Contains("_msdcs")) -and !($ZoneName.Contains("_sites")) -and !($ZoneName.Contains("_tcp")) -and !($ZoneName.Contains("_udp")) -and !($ZoneName.Contains("DomainDnsZones")) -and !($ZoneName.Contains("ForestDnsZones")))
                {
                   
                    #region "If Record is of type 'PTR'"

                    if($DnsRecordType -eq "PTR")
                    {
                        $addRvs = $ZoneName -split "\."
                        $zoneConstant = ".in-addr.arpa"
                        $ClassCAddress = $false
                        $ClassBAddress = $false
                        $ClassAAddress = $false
                        #$rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                        $rZone = "$($addRvs[0]).in-addr.arpa" #Check for Class A reverse Zone initially
                        Write-Host "`nChecking Zone if it's of Class A type: $rZone" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Checking Zone if it's of Class A type: $rZone" | Add-Content $LogFile
                        $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZone
                        $result = Invoke-Expression -Command $zoneExistsCommand
                        $ZoneExists = $result | Out-String

                         Write-Host "`nProcessing PTR Record $ZoneName" -ForegroundColor Green
                         Write-Output "`n$CurrentDate --> Processing PTR Record $ZoneName" | Add-Content $LogFile
          
                        #—– If Class A Zone Exists ——-#
                        if(!$ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST"))
                        {
                            #Sample: dnscmd /RecordAdd 10.in-addr.arpa 20.132.124 PTR TestPC.NBNTEST.local
                            $ClassAAddress = $true
                            $ClassBAddress = $false
                            $ClassCAddress = $false
                            Write-Host "`nZone is a Class A type: $rZone" -ForegroundColor Cyan
                            Write-Output "`n$CurrentDate --> Zone is a Class A type: $rZone" | Add-Content $LogFile
                            $rIP = "$($addRvs[1]).$($addRvs[2]).$($addRvs[3])"
                            $cmd = "dnscmd /RecordAdd $rZone $rIP PTR $RecordData"
                            Write-Host "`nExecuting DNSCMD RecordAdd command $cmd" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Executing DNSCMD RecordAdd command $cmd" | Add-Content $LogFile
             
                            Invoke-Expression $cmd | Out-String | Add-Content $LogFile

                        }else{

                            $ClassAAddress = $false
                            $ClassBAddress = $false
                            $ClassCAddress = $false   
                        }

                        if(($ClassAAddress -eq $false) -and ($ClassCAddress -eq $false))
                        {
                            #Check for Class B type Zone
                            $rZone = "$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                            Write-Host "`nChecking Zone if it's of Class B type: $rZone" -ForegroundColor Cyan
                            Write-Output "`n$CurrentDate --> Checking Zone if it's of Class B type: $rZone" | Add-Content $LogFile
                            $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZone
                            $result = Invoke-Expression -Command $zoneExistsCommand
                            $ZoneExists = $result | Out-String
                            $ClassBAddress = $true

                            if(!$ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST"))
                            {
                                #Sample: dnscmd /RecordAdd 228.10.in-addr.arpa 132.124 PTR TestPC.NBNTEST.local
                                $ClassAAddress = $false
                                $ClassBAddress = $true
                                $ClassCAddress = $false
                                Write-Host "`nZone is a Class B type: $rZone" -ForegroundColor Cyan
                                Write-Output "`n$CurrentDate --> Zone is a Class B type: $rZone" | Add-Content $LogFile
                                $rIP = "$($addRvs[2]).$($addRvs[3])"
                                $cmd = "dnscmd /RecordAdd $rZone $rIP PTR $RecordData"
                                Write-Host "`nExecuting DNSCMD RecordAdd command $cmd" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD RecordAdd command $cmd" | Add-Content $LogFile
             
                                Invoke-Expression $cmd | Out-String | Add-Content $LogFile

                            }else{

                                $ClassAAddress = $false
                                $ClassBAddress = $false
                                $ClassCAddress = $false
                            }
                        }

                        if(($ClassAAddress -eq $false) -and ($ClassBAddress -eq $false))#The only other possibility is a Class C Address or the zone doesn't exist
                        {
                            #Check for Class C type Zone
                            $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                            Write-Host "`nChecking Zone if it's of Class C type: $rZone" -ForegroundColor Cyan
                            Write-Output "`n$CurrentDate --> Checking Zone if it's of Class C type: $rZone" | Add-Content $LogFile
                            $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZone
                            $result = Invoke-Expression -Command $zoneExistsCommand
                            $ZoneExists = $result | Out-String
                            $ClassCAddress = $true

                            if(!$ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST"))
                            {
                                #Sample: dnscmd /RecordAdd 40.228.10.in-addr.arpa 124 PTR TestPC.NBNTEST.local
                                $ClassAAddress = $false
                                $ClassBAddress = $false
                                $ClassCAddress = $true
                                Write-Host "`nZone is a Class C type: $rZone" -ForegroundColor Cyan
                                Write-Output "`n$CurrentDate --> Zone is a Class C type: $rZone" | Add-Content $LogFile
                                $rIP = "$($addRvs[3])"
                                $cmd = "dnscmd /RecordAdd $rZone $rIP PTR $RecordData"
                                Write-Host "`nExecuting DNSCMD RecordAdd command $cmd" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD RecordAdd command $cmd" | Add-Content $LogFile
             
                                Invoke-Expression $cmd | Out-String | Add-Content $LogFile

                            }else{

                                $ClassAAddress = $false
                                $ClassBAddress = $false
                                $ClassCAddress = $false

                            }

                        }

                        $RevserseRecordCount++

                    }

                    #endregion

                    #region "If Record is of type 'A'"

                    if($DnsRecordType -eq "A-Record")
                    {

                        if(!([string]::IsNullOrEmpty($ZoneName)) -and !([string]::IsNullOrEmpty($RecordData)))
                        {
                            #Check if an extension exits

                            $CurrentForwardZone = [System.IO.Path]::GetFileNameWithoutExtension($CSVToProcess)

                            #DNSCMD Command Example: dnscmd /recordadd contoso.com Server1 A 10.100.4.10
                            Write-Host "`nProcessing A Record $ZoneName for Forward-Zone $CurrentForwardZone" -ForegroundColor Cyan
                            Write-Output "`n$CurrentDate --> Processing A Record $ZoneName for Forward-Zone $CurrentForwardZone" | Add-Content $LogFile
                            $cmdZoneAdd = "dnscmd /recordadd $CurrentForwardZone $ZoneName A $RecordData"

                            Write-Host "`nExecuting DNSCMD RecordAdd command $cmdZoneAdd" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Executing DNSCMD RecordAdd command $cmdZoneAdd" | Add-Content $LogFile
             
                            Invoke-Expression $cmdZoneAdd | Out-String | Add-Content $LogFile

                            $ARecordCount++
                        }
                    }

                    #endregion
           
              }


            }
            catch [Exception]
            {

              Write-Host "`nError unable to add zone $rZone. Error executing $cmd " -ForegroundColor Red
              Write-Output "`n$CurrentDate --> Error unable to add zone $rZone. Error executing $cmd" | Add-Content $LogFile

            }


        }

    }
 
  $ProcessingEndTime = Get-Date
  $duration = "{0:n2}" -f ($ProcessingEndTime.Subtract($ProcessingStartTime).TotalSeconds)
  $durationMinutes = [decimal]::Round($duration / 60)

  if($RevserseRecordCount -gt 0)
  {
    Write-Host "`n$RevserseRecordCount 'PTR' Record(s) have been processed for Reverse-Lookup Zones" -ForegroundColor Green
    Write-Output "`n$CurrentDate --> $RevserseRecordCount 'PTR' Record(s) have been processed for Reverse-Lookup Zones" | Add-Content $LogFile
    Write-Host "`nAll 'PTR' Record(s) have been processed Successfully." -ForegroundColor Green
    Write-Output "`n$CurrentDate --> All 'PTR' Record(s) have been processed Successfully." | Add-Content $LogFile

  }

  if($ARecordCount -gt 0)
  {

     Write-Host "`n$ARecordCount 'A' Record(s) have been processed for Forward-Lookup Zones" -ForegroundColor Green
     Write-Output "`n$CurrentDate --> $ARecordCount 'A' Record(s) have been processed for Forward-Lookup Zones" | Add-Content $LogFile
     Write-Host "`nAll 'A' Record(s) have been processed Successfully." -ForegroundColor Green
     Write-Output "`n$CurrentDate --> All 'A' Record(s) have been processed Successfully." | Add-Content $LogFile
  }

  if($MXRecordCount -gt 0)
  {

    Write-Host "`n$MXRecordCount MX Record(s) have been processed for Forward-Lookup Zones" -ForegroundColor Green
    Write-Output "`n$CurrentDate --> $MXRecordCount MX Record(s) have been processed for Forward-Lookup Zones" | Add-Content $LogFile
    Write-Host "`nAll MX Record(s) have been processed Successfully." -ForegroundColor Green
    Write-Output "`n$CurrentDate --> All MX Record(s) have been processed Successfully." | Add-Content $LogFile
  }

   Write-Host "`n--------------------------------------------------------------------------------------------------------------------" -ForegroundColor Cyan
   Write-Host "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
   Write-Host "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" -ForegroundColor Cyan
   Write-Host "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" -ForegroundColor Cyan
   Write-Host "`n--------------------------------------------------------------------------------------------------------------------`n" -ForegroundColor Cyan


  Write-Output "`n--------------------------------------------------------------------------------------------------------------------" | Add-Content $LogFile
  Write-Output "`n$CurrentDate --> Start Time......: $(Get-Date $ProcessingStartTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
  Write-Output "`n$CurrentDate --> End Time........: $(Get-Date $ProcessingEndTime -format "yyyy-MM-dd HH:mm:ss")" | Add-Content $LogFile
  Write-Output "`n$CurrentDate --> Record Processing Duration........: $durationMinutes Minutes" | Add-Content $LogFile
  Write-Output "`n--------------------------------------------------------------------------------------------------------------------`n" | Add-Content $LogFile

}



#endregion

#region "Get Zone Information"

if($GetZoneInfo -eq $true)
{

    if(!($NameOfZone -eq ""))
    {

        try{
           
             Write-Host "`nQuerying Zone Information for Dns Zone $NameOfZone" -ForegroundColor Yellow
             Write-Output "`n$CurrentDate --> Querying Zone Information for Dns Zone $NameOfZone" | Add-Content $LogFile
             $zoneQueryCommand = "dnscmd /ZoneInfo $NameOfZone"
             Write-Host "`nExecuting DNSCMD ZoneInfo command $zoneQueryCommand" -ForegroundColor Green
             Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneInfo command $zoneQueryCommand" | Add-Content $LogFile
             Invoke-Expression $zoneQueryCommand
             Invoke-Expression $zoneQueryCommand | Out-String | Add-Content $LogFile

     
        }
        catch [Exception]
        {

             Write-Host "`nError Querying Zone $NameOfZone" -ForegroundColor Red
             Write-Output "`n$CurrentDate --> Error Querying Zone $NameOfZone" | Add-Content $LogFile
             Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
             Exit

        }

    }else{
       
        Write-Host "`nNo ZoneName defined. Unable to query Zone Information...Exiting Script" -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> No ZoneName defined. Unable to query Zone Information...Exiting Script" | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }

}

#endregion

#region "Popluate DNS Reverse zone Information from Active Directory"

if($PopulateFromAD -eq $true)
{
   $ADConnected = $false
   try{
  
    Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
    Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
    $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
    $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
    $schemapartition = $schema.Name
    $RootDSC = [adsi]"LDAP://RootDSE"
    $DomNamingContext = $RootDSC.RootDomainNamingContext
    $ConfigNamingContext = $RootDSC.configurationNamingContext
    $ADConnected = $true
    Write-Host "`nConnection to Active Directory is successfull...." -ForegroundColor Cyan
    Write-Output "`n$CurrentDate --> Connection to Active Directory is successfull...." | Add-Content $LogFile
    if($ADConnected)
    {
        try{

            #Get all the Subnets in Active Directory
            $Path_ADSubnets = "LDAP://CN=Subnets,CN=Sites,$($ConfigNamingContext)"
            Write-Host "`nCollecting Active Directory Subnet information...." -ForegroundColor Cyan
            Write-Output "`n$CurrentDate --> Collecting Active Directory Subnet information...." | Add-Content $LogFile

            $AD_SiteSubnets = @(Search-AD -Filter '(&(objectClass=subnet))' `
                                                   -Properties name,location,siteobject `
                                                   -SearchRoot $Path_ADSubnets |
                                            Sort-Object Name)
            Write-Host "`nSubnets discovered successfully...." -ForegroundColor Cyan
            Write-Output "`n$CurrentDate --> Subnets discovered successfully...." | Add-Content $LogFile

            ForEach($SubNet in $AD_SiteSubnets)
            {
                $ClassAZone = $false
                $ClassBZone = $false
                $ClassCZone = $false
                #Write-Host $SubNet.Name
                $IpSubnet = $SubNet.name -split "\/"
                $IpAddr = $IpSubnet[0]
                $addRvs = $IpSubnet[0] -split "\."

                #region "Class A Reverse Zone Creation"
               
                #Check/Create Class A Reverse Zone
                if($SubNetClass -eq "ClassA")
                {
                     $rZone = "$($addRvs[0]).in-addr.arpa" #Check for Class A reverse Zone initially
                     Write-Host "`nChecking for Zone $rZone" -ForegroundColor Cyan
                     Write-Output "`n$CurrentDate --> Checking for Zone $rZone" | Add-Content $LogFile
                     $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZone
                     $result = Invoke-Expression -Command $zoneExistsCommand
                     $ZoneExists = $result | Out-String

                     if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class A zone Doesnt Exist
                      {                       
                            <#

                                If the Class A zone doesn't exist it's good, however the Class A zone
                                could be configured as a Class B or Class C Zone, so we need to check for these as well.

                            #>

                            $ClassAZone = $true

                            #Lets Check for the Class B Zone
                            #Check for Class B type Zone
                            $rZoneB = "$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                            Write-Host "`nChecking for Zone $rZoneB" -ForegroundColor Cyan
                            Write-Output "`n$CurrentDate --> Checking for Zone $rZoneB" | Add-Content $LogFile
                            $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZoneB
                            $result = Invoke-Expression -Command $zoneExistsCommand
                            $ZoneExists = $result | Out-String
                           
                            if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class B zone Doesnt Exist
                            {
                                $ClassBZone = $true
                                #Lets Check for the Class C Zone
                                #Check for Class C type Zone
                                $rZoneC = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                                Write-Host "`nChecking for Zone $rZoneC" -ForegroundColor Cyan
                                Write-Output "`n$CurrentDate --> Checking for Zone $rZoneC" | Add-Content $LogFile
                                $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZoneC
                                $result = Invoke-Expression -Command $zoneExistsCommand
                                $ZoneExists = $result | Out-String
                               
                                if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class C zone Doesnt Exist
                                {
                                    $ClassCZone = $true
                                }else{

                                    $ZoneFound = "$IpAddr already exists as a Class C Zone $rZoneC"
                                }

                               
                            }
                            else{

                                $ZoneFound = "$IpAddr already exists as a Class B Zone $rZoneB"
                            }
                                             

                      }else{

                        $ZoneFound = "$rZone already exists"
                      }
                     
                      #Ok the Reverse Zone doesn't exist at all so we can now create it
                      if(($ClassAZone -eq $true) -and ($ClassBZone -eq $true) -and ($ClassCZone -eq $true))
                      {
                           $zoneAddCommand ="dnscmd /ZoneAdd $rZone /DSPrimary" #Add and Active Directory Integrated Zone Only
                            Write-Host "`nExecuting DNSCMD ZoneAdd command $zoneAddCommand" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $zoneAddCommand" | Add-Content $LogFile
                            #Invoke-Expression $zoneCommand
                            Invoke-Expression $zoneAddCommand | Out-String | Add-Content $LogFile
                            Write-Host "`nReverse Lookup Zone $rZone has been created successfully" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Reverse Lookup Zone $rZone has been created successfully" | Add-Content $LogFile
                            if($AllowDynamicUpdates -eq $true) #Secure Updates Only
                            {
                                <#

                                For dynamic updates the following decimal values can be used
                   
                                0 --> No Dynamic updates
                                1 --> Allow both Secure and non-Secure Dynamic Updates
                                2--> Allow only Secure Dynamic Updates (Default setting for script)

                                #>

                                $zoneDynamicUpdate ="dnscmd /Config $rZone /AllowUpdate 2" #Enable Dynamic Updates on Zones
                                Write-Host "`nExecuting DNSCMD DynamicUpdate command $zoneDynamicUpdate" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD DynamicUpdate command $zoneDynamicUpdate" | Add-Content $LogFile
        
                                #Invoke-Expression $zoneDynamicUpdate
                                Invoke-Expression $zoneDynamicUpdate | Out-String | Add-Content $LogFile
                                Write-Host "`nZone $ForwardZoneName has been configured for DynamicUpdates" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Zone $ForwardZoneName has been configured for DynamicUpdates" | Add-Content $LogFile
           
                            }

                                   
                      }else{
                       
                             Write-Host "`n$ZoneFound" -ForegroundColor Cyan
                             Write-Output "`n$CurrentDate --> $ZoneFound" | Add-Content $LogFile
           

                      }

                }

                #endregion

                #region "Class B Reverse Zone Creation"

                if($SubNetClass -eq "ClassB")
                {

                    #Lets Check for the Class B Zone
                    #Check for Class B type Zone
                    $rZone = "$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                    Write-Host "`nChecking for Zone $rZone" -ForegroundColor Cyan
                    Write-Output "`n$CurrentDate --> Checking for Zone $rZone" | Add-Content $LogFile
                    $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZone
                    $result = Invoke-Expression -Command $zoneExistsCommand
                    $ZoneExists = $result | Out-String

                    if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class B zone Doesnt Exist
                    {

                        $ClassBZone = $true
                        #Lets Check for the Class C Zone
                        #Check for Class C type Zone
                        $rZoneC = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                        Write-Host "`nChecking for Zone $rZoneC" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Checking for Zone $rZoneC" | Add-Content $LogFile
                        $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZoneC
                        $result = Invoke-Expression -Command $zoneExistsCommand
                        $ZoneExists = $result | Out-String

                        if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class C zone Doesnt Exist
                        {
                           $ClassCZone = $true
                           #We need to also check for the Class A Zone so that Zones don't overlap each other.
                           #Need to keep DNS Clean

                           $rZoneA = "$($addRvs[0]).in-addr.arpa" #Check for Class A reverse Zone initially
                           Write-Host "`nChecking for Zone $rZoneA" -ForegroundColor Cyan
                           Write-Output "`n$CurrentDate --> Checking for Zone $rZoneA" | Add-Content $LogFile
                           $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZoneA
                           $result = Invoke-Expression -Command $zoneExistsCommand
                           $ZoneExists = $result | Out-String

                           if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class A zone Doesnt Exist
                           {
                                $ClassAZone = $true
                           }else{

                               $ZoneFound = "$IpAddr already exists as a Class A Zone $rZoneA"
                           }

                        }else{

                           $ZoneFound = "$IpAddr already exists as a Class C Zone $rZoneC"
                        }


                    }else{
                       
                        $ZoneFound = "$rZone already exists"

                    }
                   
                      #Ok the Reverse Zone doesn't exist at all so we can now create it
                      if(($ClassAZone -eq $true) -and ($ClassBZone -eq $true) -and ($ClassCZone -eq $true))
                      {
                           $zoneAddCommand ="dnscmd /ZoneAdd $rZone /DSPrimary" #Add and Active Directory Integrated Zone Only
                            Write-Host "`nExecuting DNSCMD ZoneAdd command $zoneAddCommand" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $zoneAddCommand" | Add-Content $LogFile
                            #Invoke-Expression $zoneCommand
                            Invoke-Expression $zoneAddCommand | Out-String | Add-Content $LogFile
                            Write-Host "`nReverse Lookup Zone $rZone has been created successfully" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Reverse Lookup Zone $rZone has been created successfully" | Add-Content $LogFile
                            if($AllowDynamicUpdates -eq $true) #Secure Updates Only
                            {
                                <#

                                For dynamic updates the following decimal values can be used
                   
                                0 --> No Dynamic updates
                                1 --> Allow both Secure and non-Secure Dynamic Updates
                                2--> Allow only Secure Dynamic Updates (Default setting for script)

                                #>

                                $zoneDynamicUpdate ="dnscmd /Config $rZone /AllowUpdate 2" #Enable Dynamic Updates on Zones
                                Write-Host "`nExecuting DNSCMD DynamicUpdate command $zoneDynamicUpdate" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD DynamicUpdate command $zoneDynamicUpdate" | Add-Content $LogFile
        
                                #Invoke-Expression $zoneDynamicUpdate
                                Invoke-Expression $zoneDynamicUpdate | Out-String | Add-Content $LogFile
                                Write-Host "`nZone $ForwardZoneName has been configured for DynamicUpdates" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Zone $ForwardZoneName has been configured for DynamicUpdates" | Add-Content $LogFile
           
                            }

                                   
                      }else{
                       
                             Write-Host "`n$ZoneFound" -ForegroundColor Cyan
                             Write-Output "`n$CurrentDate --> $ZoneFound" | Add-Content $LogFile
           

                      }

                }

                #endregion

                #region "Class C Reverse Zone Creation"

                if($SubNetClass -eq "ClassC")
                {

                    #Lets Check for the Class C Zone
                    #Check for Class C type Zone
                    $rZone = "$($addRvs[2]).$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                    Write-Host "`nChecking for Zone $rZone" -ForegroundColor Cyan
                    Write-Output "`n$CurrentDate --> Checking for Zone $rZone" | Add-Content $LogFile
                    $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZone
                    $result = Invoke-Expression -Command $zoneExistsCommand
                    $ZoneExists = $result | Out-String

                    if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class C zone Doesnt Exist
                    {
                        $ClassCZone = $true
                        #Lets Check for the Class B Zone
                        #Check for Class B type Zone
                        $rZoneB = "$($addRvs[1]).$($addRvs[0]).in-addr.arpa"
                        Write-Host "`nChecking for Zone $rZoneB" -ForegroundColor Cyan
                        Write-Output "`n$CurrentDate --> Checking for Zone $rZoneB" | Add-Content $LogFile
                        $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZoneB
                        $result = Invoke-Expression -Command $zoneExistsCommand
                        $ZoneExists = $result | Out-String

                        if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class B zone Doesnt Exist
                        {
                            $ClassBZone = $true

                            #We need to also check for the Class A Zone so that Zones don't overlap each other.
                            #Need to keep DNS Clean

                            $rZoneA = "$($addRvs[0]).in-addr.arpa" #Check for Class A reverse Zone initially
                            Write-Host "`nChecking for Zone $rZoneA" -ForegroundColor Cyan
                            Write-Output "`n$CurrentDate --> Checking for Zone $rZoneA" | Add-Content $LogFile
                            $zoneExistsCommand = "dnscmd /ZoneInfo " + $rZoneA
                            $result = Invoke-Expression -Command $zoneExistsCommand
                            $ZoneExists = $result | Out-String

                            if($ZoneExists.Contains("DNS_ERROR_ZONE_DOES_NOT_EXIST")) #Class A zone Doesnt Exist
                            {
                                $ClassAZone = $true
                            }else{

                               $ZoneFound = "$IpAddr already exists as a Class A Zone $rZoneA"
                            }

                        }else{
                            $ZoneFound = "$IpAddr already exists as a Class B Zone $rZoneB"

                        }
                    }else{
                        $ZoneFound = "$rZone already exists"
                    }

                      #Ok the Reverse Zone doesn't exist at all so we can now create it
                      if(($ClassAZone -eq $true) -and ($ClassBZone -eq $true) -and ($ClassCZone -eq $true))
                      {

                            $zoneAddCommand ="dnscmd /ZoneAdd $rZone /DSPrimary" #Add and Active Directory Integrated Zone Only
                            Write-Host "`nExecuting DNSCMD ZoneAdd command $zoneAddCommand" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Executing DNSCMD ZoneAdd command $zoneAddCommand" | Add-Content $LogFile
                            #Invoke-Expression $zoneCommand
                            Invoke-Expression $zoneAddCommand | Out-String | Add-Content $LogFile
                            Write-Host "`nReverse Lookup Zone $rZone has been created successfully" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Reverse Lookup Zone $rZone has been created successfully" | Add-Content $LogFile
                            if($AllowDynamicUpdates -eq $true) #Secure Updates Only
                            {
                                <#

                                For dynamic updates the following decimal values can be used
                   
                                0 --> No Dynamic updates
                                1 --> Allow both Secure and non-Secure Dynamic Updates
                                2--> Allow only Secure Dynamic Updates (Default setting for script)

                                #>

                                $zoneDynamicUpdate ="dnscmd /Config $rZone /AllowUpdate 2" #Enable Dynamic Updates on Zones
                                Write-Host "`nExecuting DNSCMD DynamicUpdate command $zoneDynamicUpdate" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Executing DNSCMD DynamicUpdate command $zoneDynamicUpdate" | Add-Content $LogFile
        
                                #Invoke-Expression $zoneDynamicUpdate
                                Invoke-Expression $zoneDynamicUpdate | Out-String | Add-Content $LogFile
                                Write-Host "`nZone $ForwardZoneName has been configured for DynamicUpdates" -ForegroundColor Green
                                Write-Output "`n$CurrentDate --> Zone $ForwardZoneName has been configured for DynamicUpdates" | Add-Content $LogFile
           
                            }

                      }else{
                             Write-Host "`n$ZoneFound" -ForegroundColor Cyan
                             Write-Output "`n$CurrentDate --> $ZoneFound" | Add-Content $LogFile

                      }

                }


                #endregion
            }

        }
        catch [Exception]
        {
            $ADConnected = $false
            Write-Host "`nUnable to enumerate Active Directory Subnets....Exiting Script" -ForegroundColor Red
            Write-Output "`n$CurrentDate --> Unable to enumerate Active Directory Subnets....Exiting Script" | Add-Content $LogFile
            Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
            Exit

        }
       
    }
  
   }
   catch [Exception]
   {
    $ADConnected = $false
    Write-Host "`nUnable to connect to Active Directory. Exiting Script...." -ForegroundColor Red
    Write-Output "`n$CurrentDate --> Unable to connect to Active Directory. Exiting Script...." | Add-Content $LogFile
    Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
    Exit
   }

}

#endregion

#region "Enable/Disable Aging on All Zones and DNS Servers"

if($DnsZoneAging -eq $true)
{

    if($EnableAging -eq $true)
    {
        if($AllActiveDnsServers -eq $true)
        {

            $ADConnected = $false

            try{
                Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
                Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
                $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
                $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
                $schemapartition = $schema.Name
                $RootDSC = [adsi]"LDAP://RootDSE"
                $DomNamingContext = $RootDSC.RootDomainNamingContext
                $ConfigNamingContext = $RootDSC.configurationNamingContext
                $DomainDN = 'dc=' + $Forest.Domains.Name.Replace('.', ',dc=')
                $ADConnected = $true
                Write-Host "`nConnection to Active Directory is successfull...." -ForegroundColor Cyan
                Write-Output "`n$CurrentDate --> Connection to Active Directory is successfull...." | Add-Content $LogFile

                if($ADConnected)
                {
                    #Get All Registered DNS Servers
                    #Assuming that all DC's/GC's are all DNS Servers
                    $GCs = $forest.FindAllGlobalCatalogs()
                    $GCNames = @($GCs | Select Name)
                    $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name)
                    $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name))

                    #Get All AD Integrated Zones
                 
                    #region AD Integrated DNS Zones
                   
                                     
                    $Path_DNSDomainZoneDN = "LDAP://DC=DomainDnsZones,$DomainDN"
                    if ([ADSI]::Exists($Path_DNSDomainZoneDN))
                    {
                        $AD_DomainZones = @(Search-AD -SearchRoot $Path_DNSDomainZoneDN `
                                                      -Filter '(objectclass=dnsZone)' `
                                                      -Properties name,whencreated,whenchanged,distinguishedName)
                       
                    }
                    #endregion AD Integrated DNS Zones

                    #Enable Aging/Scavenging on NS servers as well as all zones
                    Foreach($ServerName in $ForestDCs)
                    {
                         $DNSName = $ServerName.name
                         $agingCommand = "dnscmd $DNSName /config /defaultagingstate 1"
                         Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                         Write-Host "`nAging and Scavenging has been enabled on DNS Server $DNSName" -ForegroundColor Green
                         Write-Output "`n$CurrentDate --> Aging and Scavenging has been enabled on DNS Server $DNSName" | Add-Content $LogFile
                       
                    }

                    #Enable Aging/Scavenging on All Zones
                    ForEach($CurrentZone in $AD_DomainZones)
                    {
                        $ZoneName = $CurrentZone.Name
                        if(!($ZoneName -eq "RootDNSServers"))
                        {
                       
                            $agingCommand = "dnscmd /config $ZoneName /aging 1"
                            Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                            Write-Host "`nAging and Scavenging has been enabled on zone $ZoneName" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Aging and Scavenging has been enabled on zone $ZoneName" | Add-Content $LogFile

                        }
          

                    }


                }

            }
            catch [Exception]
            {
                $ADConnected = $false
                Write-Host "`nUnable to connect to Active Directory. Exiting Script...." -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Unable to connect to Active Directory. Exiting Script...." | Add-Content $LogFile
                Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
                Exit

            }


        }else{
            if(!([string]::IsNullOrEmpty($DnsServerName)))
            {
                $agingCommand = "dnscmd $DnsServerName /config /defaultagingstate 1"
                Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                Write-Host "`nAging and Scavenging has been enabled on DNS Server $DnsServerName" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Aging and Scavenging has been enabled on DNS Server $DnsServerName" | Add-Content $LogFile
                       
            }else{
                $agingCommand = "dnscmd /config /defaultagingstate 1"
                Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                Write-Host "`nAging and Scavenging has been enabled on local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Aging and Scavenging has been enabled on local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
          

            }

        }


    }else{

       if($AllActiveDnsServers -eq $true)
        {

            $ADConnected = $false

            try{
                Write-Host "`nConnecting to Active Directory...." -ForegroundColor Yellow
                Write-Output "`n$CurrentDate --> Connecting to Active Directory...." | Add-Content $LogFile
                $schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
                $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
                $schemapartition = $schema.Name
                $RootDSC = [adsi]"LDAP://RootDSE"
                $DomNamingContext = $RootDSC.RootDomainNamingContext
                $ConfigNamingContext = $RootDSC.configurationNamingContext
                $DomainDN = 'dc=' + $Forest.Domains.Name.Replace('.', ',dc=')
                $ADConnected = $true
                Write-Host "`nConnection to Active Directory is successfull...." -ForegroundColor Cyan
                Write-Output "`n$CurrentDate --> Connection to Active Directory is successfull...." | Add-Content $LogFile

                if($ADConnected)
                {
                    #Get All Registered DNS Servers
                    #Assuming that all DC's/GC's are all DNS Servers
                    $GCs = $forest.FindAllGlobalCatalogs()
                    $GCNames = @($GCs | Select Name)
                    $ForestDCs = @($forest.Domains | %{$_.DomainControllers} | Select Name)
                    $ForestGCs = @((($GCs | Sort-Object -Property Name) | Select Name))

                    #Get All AD Integrated Zones
                    #region AD Integrated DNS Zones
                   
                                     
                    $Path_DNSDomainZoneDN = "LDAP://DC=DomainDnsZones,$DomainDN"
                    if ([ADSI]::Exists($Path_DNSDomainZoneDN))
                    {
                        $AD_DomainZones = @(Search-AD -SearchRoot $Path_DNSDomainZoneDN `
                                                      -Filter '(objectclass=dnsZone)' `
                                                      -Properties name,whencreated,whenchanged,distinguishedName)
                       
                    }
                    #endregion AD Integrated DNS Zones

                    #Disable Aging/Scavenging on NS servers as well as all zones
                    Foreach($ServerName in $ForestDCs)
                    {
                         $DNSName = $ServerName.name
                         $agingCommand = "dnscmd $DNSName /config /defaultagingstate 0"
                         Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                         Write-Host "`nAging and Scavenging has been disabled on DNS Server $DNSName" -ForegroundColor Green
                         Write-Output "`n$CurrentDate --> Aging and Scavenging has been disabled on DNS Server $DNSName" | Add-Content $LogFile
                       
                    }

                    #Disable Aging/Scavenging on All Zones
                    ForEach($CurrentZone in $AD_DomainZones)
                    {
                        $ZoneName = $CurrentZone.Name
                        if(!($ZoneName -eq "RootDNSServers"))
                        {
                       
                            $agingCommand = "dnscmd /config $ZoneName /aging 0"
                            Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                            Write-Host "`nAging and Scavenging has been disbaled on zone $ZoneName" -ForegroundColor Green
                            Write-Output "`n$CurrentDate --> Aging and Scavenging has been disabled on zone $ZoneName" | Add-Content $LogFile

                        }
          

                    }

                }

            }
            catch [Exception]
            {
                $ADConnected = $false
                Write-Host "`nUnable to connect to Active Directory. Exiting Script...." -ForegroundColor Red
                Write-Output "`n$CurrentDate --> Unable to connect to Active Directory. Exiting Script...." | Add-Content $LogFile
                Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
                Exit

            }


        }else{
            if(!([string]::IsNullOrEmpty($DnsServerName)))
            {
                $agingCommand = "dnscmd $DnsServerName /config /defaultagingstate 0"
                Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                Write-Host "`nAging and Scavenging has been disabled on DNS Server $DnsServerName" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Aging and Scavenging has been disabled on DNS Server $DnsServerName" | Add-Content $LogFile
                       
            }else{
                $agingCommand = "dnscmd /config /defaultagingstate 0"
                Invoke-Expression $agingCommand | Out-String | Add-Content $LogFile
                Write-Host "`nAging and Scavenging has been disabled on local DNS Server $env:COMPUTERNAME" -ForegroundColor Green
                Write-Output "`n$CurrentDate --> Aging and Scavenging has been disabled on local DNS Server $env:COMPUTERNAME" | Add-Content $LogFile
          

            }

        }


    }
}

#endregion

#region "Repair DNS Records (i.e., SRV Records, NameServer records etc....)

if($RepairDnsRecords)
{
    try{

        $cmdFlushDns = "ipconfig /flushdns"
        $cmdRegisterDNS = "ipconfig /registerdns"
        $cmdNlTestRegisterDns = "nltest /dsregdns"

        Write-Host "`n"
        Write-Host "`nFlushing DNS cache entries" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Flushing DNS cache entries" | Add-Content $LogFile
        Write-Host "`n"

        Invoke-Expression $cmdFlushDns
        Invoke-Expression $cmdFlushDns | Out-String | Add-Content $LogFile

        Write-Host "`nDNS cache has been flushed out" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> DNS cache has been flushed out" | Add-Content $LogFile
        Write-Host "`n"

        Write-Host "`nRegistering DNS...." -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Registering DNS...." | Add-Content $LogFile
        Write-Host "`n"

        Invoke-Expression $cmdRegisterDNS
        Invoke-Expression $cmdRegisterDNS | Out-String | Add-Content $LogFile

        Write-Host "`nDNS has been registered successfully" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> DNS has been registered successfully" | Add-Content $LogFile
        Write-Host "`n"

        Write-Host "`nReparing Name Server Records...." -ForegroundColor Green
        Write-Output "`n$CurrentDate --> Reparing Name Server Records...." | Add-Content $LogFile
        Write-Host "`n"

        Invoke-Expression $cmdNlTestRegisterDns
        Invoke-Expression $cmdNlTestRegisterDns | Out-String | Add-Content $LogFile

        Write-Host "`nDNS Name server Records have been repaired successfully" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> DNS Name server Records have been repaired successfully" | Add-Content $LogFile
        Write-Host "`n"

        Write-Host "`nDNS has been repaired successfully" -ForegroundColor Green
        Write-Output "`n$CurrentDate --> DNS has been repaired successfully" | Add-Content $LogFile
        Write-Host "`n"

        Write-Host "`n****NOTE**** Restart the server for the changes to take effect" -ForegroundColor Cyan
        Write-Output "`n$CurrentDate --> ****NOTE**** Restart the server for the changes to take effect" | Add-Content $LogFile
        Write-Host "`n"


    }
    catch [Exception]
    {
        Write-Host "`nError reparing DNS. Exiting Script...." -ForegroundColor Red
        Write-Output "`n$CurrentDate --> Error reparing DNS. Exiting Script...." | Add-Content $LogFile
        Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile
        Exit

    }



}


#endregion
   

Write-Output "`n********************************************************************** Logging Finished *****************************************************************" | Add-Content $LogFile

#endregion


Enjoy. As always please leave your comments regarding this article.

Configure-DNS.ps1 (157.6KB)