PSWinDocumentation.DNS.psm1

function Get-WinADForestDetails {
    [CmdletBinding()]
    param([alias('ForestName')][string] $Forest,
        [string[]] $ExcludeDomains,
        [string[]] $ExcludeDomainControllers,
        [alias('Domain', 'Domains')][string[]] $IncludeDomains,
        [alias('DomainControllers', 'ComputerName')][string[]] $IncludeDomainControllers,
        [switch] $SkipRODC,
        [string] $Filter = '*',
        [switch] $TestAvailability,
        [ValidateSet('All', 'Ping', 'WinRM', 'PortOpen', 'Ping+WinRM', 'Ping+PortOpen', 'WinRM+PortOpen')] $Test = 'All',
        [int[]] $Ports = 135,
        [int] $PortsTimeout = 100,
        [int] $PingCount = 1,
        [switch] $Extended,
        [System.Collections.IDictionary] $ExtendedForestInformation)
    if ($Global:ProgressPreference -ne 'SilentlyContinue') {
        $TemporaryProgress = $Global:ProgressPreference
        $Global:ProgressPreference = 'SilentlyContinue'
    }
    if (-not $ExtendedForestInformation) {
        $Findings = [ordered] @{ }
        try { if ($Forest) { $ForestInformation = Get-ADForest -ErrorAction Stop -Identity $Forest } else { $ForestInformation = Get-ADForest -ErrorAction Stop } } catch {
            Write-Warning "Get-WinADForestDetails - Error discovering DC for Forest - $($_.Exception.Message)"
            return
        }
        if (-not $ForestInformation) { return }
        $Findings['Forest'] = $ForestInformation
        $Findings['ForestDomainControllers'] = @()
        $Findings['QueryServers'] = @{ }
        $Findings['DomainDomainControllers'] = @{ }
        [Array] $Findings['Domains'] = foreach ($_ in $ForestInformation.Domains) {
            if ($IncludeDomains) {
                if ($_ -in $IncludeDomains) { $_.ToLower() }
                continue
            }
            if ($_ -notin $ExcludeDomains) { $_.ToLower() }
        }
        [Array] $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) {
            try {
                $DC = Get-ADDomainController -DomainName $Domain -Discover -ErrorAction Stop
                $OrderedDC = [ordered] @{Domain = $DC.Domain
                    Forest = $DC.Forest
                    HostName = [Array] $DC.HostName
                    IPv4Address = $DC.IPv4Address
                    IPv6Address = $DC.IPv6Address
                    Name = $DC.Name
                    Site = $DC.Site
                }
            } catch {
                Write-Warning "Get-WinADForestDetails - Error discovering DC for domain $Domain - $($_.Exception.Message)"
                continue
            }
            if ($Domain -eq $Findings['Forest']['Name']) { $Findings['QueryServers']['Forest'] = $OrderedDC }
            $Findings['QueryServers']["$Domain"] = $OrderedDC
            [Array] $AllDC = try {
                try { $DomainControllers = Get-ADDomainController -Filter $Filter -Server $DC.HostName[0] -ErrorAction Stop } catch {
                    Write-Warning "Get-WinADForestDetails - Error listing DCs for domain $Domain - $($_.Exception.Message)"
                    continue
                }
                foreach ($S in $DomainControllers) {
                    if ($IncludeDomainControllers.Count -gt 0) { If (-not $IncludeDomainControllers[0].Contains('.')) { if ($S.Name -notin $IncludeDomainControllers) { continue } } else { if ($S.HostName -notin $IncludeDomainControllers) { continue } } }
                    if ($ExcludeDomainControllers.Count -gt 0) { If (-not $ExcludeDomainControllers[0].Contains('.')) { if ($S.Name -in $ExcludeDomainControllers) { continue } } else { if ($S.HostName -in $ExcludeDomainControllers) { continue } } }
                    $Server = [ordered] @{Domain = $Domain
                        HostName = $S.HostName
                        Name = $S.Name
                        Forest = $ForestInformation.RootDomain
                        Site = $S.Site
                        IPV4Address = $S.IPV4Address
                        IPV6Address = $S.IPV6Address
                        IsGlobalCatalog = $S.IsGlobalCatalog
                        IsReadOnly = $S.IsReadOnly
                        IsSchemaMaster = ($S.OperationMasterRoles -contains 'SchemaMaster')
                        IsDomainNamingMaster = ($S.OperationMasterRoles -contains 'DomainNamingMaster')
                        IsPDC = ($S.OperationMasterRoles -contains 'PDCEmulator')
                        IsRIDMaster = ($S.OperationMasterRoles -contains 'RIDMaster')
                        IsInfrastructureMaster = ($S.OperationMasterRoles -contains 'InfrastructureMaster')
                        OperatingSystem = $S.OperatingSystem
                        OperatingSystemVersion = $S.OperatingSystemVersion
                        OperatingSystemLong = ConvertTo-OperatingSystem -OperatingSystem $S.OperatingSystem -OperatingSystemVersion $S.OperatingSystemVersion
                        LdapPort = $S.LdapPort
                        SslPort = $S.SslPort
                        DistinguishedName = $S.ComputerObjectDN
                        Pingable = $null
                        WinRM = $null
                        PortOpen = $null
                        Comment = ''
                    }
                    if ($TestAvailability) {
                        if ($Test -eq 'All' -or $Test -like 'Ping*') { $Server.Pingable = Test-Connection -ComputerName $Server.IPV4Address -Quiet -Count $PingCount }
                        if ($Test -eq 'All' -or $Test -like '*WinRM*') { $Server.WinRM = (Test-WinRM -ComputerName $Server.HostName).Status }
                        if ($Test -eq 'All' -or '*PortOpen*') { $Server.PortOpen = (Test-ComputerPort -Server $Server.HostName -PortTCP $Ports -Timeout $PortsTimeout).Status }
                    }
                    [PSCustomObject] $Server
                }
            } catch {
                [PSCustomObject]@{Domain = $Domain
                    HostName = ''
                    Name = ''
                    Forest = $ForestInformation.RootDomain
                    IPV4Address = ''
                    IPV6Address = ''
                    IsGlobalCatalog = ''
                    IsReadOnly = ''
                    Site = ''
                    SchemaMaster = $false
                    DomainNamingMasterMaster = $false
                    PDCEmulator = $false
                    RIDMaster = $false
                    InfrastructureMaster = $false
                    LdapPort = ''
                    SslPort = ''
                    DistinguishedName = ''
                    Pingable = $null
                    WinRM = $null
                    PortOpen = $null
                    Comment = $_.Exception.Message -replace "`n", " " -replace "`r", " "
                }
            }
            if ($SkipRODC) { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC | Where-Object { $_.IsReadOnly -eq $false } } else { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC }
            [Array] $Findings['DomainDomainControllers'][$Domain]
        }
        if ($Extended) {
            $Findings['DomainsExtended'] = @{ }
            foreach ($DomainEx in $Findings['Domains']) {
                try { $Findings['DomainsExtended'][$DomainEx] = Get-ADDomain -Server $Findings['QueryServers'][$DomainEx].HostName[0] } catch {
                    Write-Warning "Get-WinADForestDetails - Error gathering Domain Information for domain $DomainEx - $($_.Exception.Message)"
                    continue
                }
            }
        }
        if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress }
        $Findings
    } else {
        $Findings = Copy-Dictionary -Dictionary $ExtendedForestInformation
        [Array] $Findings['Domains'] = foreach ($_ in $Findings.Domains) {
            if ($IncludeDomains) {
                if ($_ -in $IncludeDomains) { $_.ToLower() }
                continue
            }
            if ($_ -notin $ExcludeDomains) { $_.ToLower() }
        }
        foreach ($_ in [string[]] $Findings.DomainDomainControllers.Keys) { if ($_ -notin $Findings.Domains) { $Findings.DomainDomainControllers.Remove($_) } }
        foreach ($_ in [string[]] $Findings.QueryServers.Keys) { if ($_ -notin $Findings.Domains -and $_ -ne 'Forest') { $Findings.QueryServers.Remove($_) } }
        [Array] $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) {
            [Array] $AllDC = foreach ($S in $Findings.DomainDomainControllers["$Domain"]) {
                if ($IncludeDomainControllers.Count -gt 0) { If (-not $IncludeDomainControllers[0].Contains('.')) { if ($S.Name -notin $IncludeDomainControllers) { continue } } else { if ($S.HostName -notin $IncludeDomainControllers) { continue } } }
                if ($ExcludeDomainControllers.Count -gt 0) { If (-not $ExcludeDomainControllers[0].Contains('.')) { if ($S.Name -in $ExcludeDomainControllers) { continue } } else { if ($S.HostName -in $ExcludeDomainControllers) { continue } } }
                $S
            }
            if ($SkipRODC) { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC | Where-Object { $_.IsReadOnly -eq $false } } else { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC }
            [Array] $Findings['DomainDomainControllers'][$Domain]
        }
        $Findings
    }
}
function ConvertTo-OperatingSystem {
    [CmdletBinding()]
    param([string] $OperatingSystem,
        [string] $OperatingSystemVersion)
    if ($OperatingSystem -like '*Windows 10*') {
        $Systems = @{'10.0 (18363)' = "Windows 10 1909"
            '10.0 (18362)' = "Windows 10 1903"
            '10.0 (17763)' = "Windows 10 1809"
            '10.0 (17134)' = "Windows 10 1803"
            '10.0 (16299)' = "Windows 10 1709"
            '10.0 (15063)' = "Windows 10 1703"
            '10.0 (14393)' = "Windows 10 1607"
            '10.0 (10586)' = "Windows 10 1511"
            '10.0 (10240)' = "Windows 10 1507"
            '10.0 (18898)' = 'Windows 10 Insider Preview'
            '10.0.18363' = "Windows 10 1909"
            '10.0.18362' = "Windows 10 1903"
            '10.0.17763' = "Windows 10 1809"
            '10.0.17134' = "Windows 10 1803"
            '10.0.16299' = "Windows 10 1709"
            '10.0.15063' = "Windows 10 1703"
            '10.0.14393' = "Windows 10 1607"
            '10.0.10586' = "Windows 10 1511"
            '10.0.10240' = "Windows 10 1507"
            '10.0.18898' = 'Windows 10 Insider Preview'
        }
        $System = $Systems[$OperatingSystemVersion]
        if (-not $System) { $System = $OperatingSystem }
    } elseif ($OperatingSystem -like '*Windows Server*') {
        $Systems = @{'5.2 (3790)' = 'Windows Server 2003'
            '6.1 (7601)' = 'Windows Server 2008 R2'
            '10.0 (18362)' = "Windows Server, version 1903 (Semi-Annual Channel) 1903"
            '10.0 (17763)' = "Windows Server 2019 (Long-Term Servicing Channel) 1809"
            '10.0 (17134)' = "Windows Server, version 1803 (Semi-Annual Channel) 1803"
            '10.0 (14393)' = "Windows Server 2016 (Long-Term Servicing Channel) 1607"
            '10.0.18362' = "Windows Server, version 1903 (Semi-Annual Channel) 1903"
            '10.0.17763' = "Windows Server 2019 (Long-Term Servicing Channel) 1809"
            '10.0.17134' = "Windows Server, version 1803 (Semi-Annual Channel) 1803"
            '10.0.14393' = "Windows Server 2016 (Long-Term Servicing Channel) 1607"
        }
        $System = $Systems[$OperatingSystemVersion]
        if (-not $System) { $System = $OperatingSystem }
    } else { $System = $OperatingSystem }
    if ($System) { $System } else { 'Unknown' }
}
function Test-ComputerPort {
    [CmdletBinding()]
    param ([alias('Server')][string[]] $ComputerName,
        [int[]] $PortTCP,
        [int[]] $PortUDP,
        [int]$Timeout = 5000)
    begin {
        if ($Global:ProgressPreference -ne 'SilentlyContinue') {
            $TemporaryProgress = $Global:ProgressPreference
            $Global:ProgressPreference = 'SilentlyContinue'
        }
    }
    process {
        foreach ($Computer in $ComputerName) {
            foreach ($P in $PortTCP) {
                $Output = [ordered] @{'ComputerName' = $Computer
                    'Port' = $P
                    'Protocol' = 'TCP'
                    'Status' = $null
                    'Summary' = $null
                    'Response' = $null
                }
                $TcpClient = Test-NetConnection -ComputerName $Computer -Port $P -InformationLevel Detailed -WarningAction SilentlyContinue
                if ($TcpClient.TcpTestSucceeded) {
                    $Output['Status'] = $TcpClient.TcpTestSucceeded
                    $Output['Summary'] = "TCP $P Successful"
                } else {
                    $Output['Status'] = $false
                    $Output['Summary'] = "TCP $P Failed"
                    $Output['Response'] = $Warnings
                }
                [PSCustomObject]$Output
            }
            foreach ($P in $PortUDP) {
                $Output = [ordered] @{'ComputerName' = $Computer
                    'Port' = $P
                    'Protocol' = 'UDP'
                    'Status' = $null
                    'Summary' = $null
                }
                $UdpClient = [System.Net.Sockets.UdpClient]::new($Computer, $P)
                $UdpClient.Client.ReceiveTimeout = $Timeout
                $Encoding = [System.Text.ASCIIEncoding]::new()
                $byte = $Encoding.GetBytes("Evotec")
                [void]$UdpClient.Send($byte, $byte.length)
                $RemoteEndpoint = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any, 0)
                try {
                    $Bytes = $UdpClient.Receive([ref]$RemoteEndpoint)
                    [string]$Data = $Encoding.GetString($Bytes)
                    If ($Data) {
                        $Output['Status'] = $true
                        $Output['Summary'] = "UDP $P Successful"
                        $Output['Response'] = $Data
                    }
                } catch {
                    $Output['Status'] = $false
                    $Output['Summary'] = "UDP $P Failed"
                    $Output['Response'] = $_.Exception.Message
                }
                $UdpClient.Close()
                $UdpClient.Dispose()
                [PSCustomObject]$Output
            }
        }
    }
    end { if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress } }
}
function Test-WinRM {
    [CmdletBinding()]
    param ([alias('Server')][string[]] $ComputerName)
    $Output = foreach ($Computer in $ComputerName) {
        $Test = [PSCustomObject] @{Output = $null
            Status = $null
            ComputerName = $Computer
        }
        try {
            $Test.Output = Test-WSMan -ComputerName $Computer -ErrorAction Stop
            $Test.Status = $true
        } catch { $Test.Status = $false }
        $Test
    }
    $Output
}
function Get-WinDnsRootHint {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN)
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    foreach ($Computer in $ComputerName) {
        $ServerRootHints = Get-DnsServerRootHint -ComputerName $Computer
        foreach ($_ in $ServerRootHints.IPAddress) {
            [PSCustomObject] @{DistinguishedName = $_.DistinguishedName
                HostName = $_.HostName
                RecordClass = $_.RecordClass
                IPv4Address = $_.RecordData.IPv4Address.IPAddressToString
                IPv6Address = $_.RecordData.IPv6Address.IPAddressToString
                RecordType = $_.RecordType
                Timestamp = $_.Timestamp
                TimeToLive = $_.TimeToLive
                Type = $_.Type
                GatheredFrom = $Computer
            }
        }
    }
}
function Get-WinDnsServerCache {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN)
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    foreach ($Computer in $ComputerName) {
        $DnsServerCache = Get-DnsServerCache -ComputerName $Computer
        foreach ($_ in $DnsServerCache) {
            [PSCustomObject] @{DistinguishedName = $_.DistinguishedName
                IsAutoCreated = $_.IsAutoCreated
                IsDsIntegrated = $_.IsDsIntegrated
                IsPaused = $_.IsPaused
                IsReadOnly = $_.IsReadOnly
                IsReverseLookupZone = $_.IsReverseLookupZone
                IsShutdown = $_.IsShutdown
                ZoneName = $_.ZoneName
                ZoneType = $_.ZoneType
                EnablePollutionProtection = $_.EnablePollutionProtection
                IgnorePolicies = $_.IgnorePolicies
                LockingPercent = $_.LockingPercent
                MaxKBSize = $_.MaxKBSize
                MaxNegativeTtl = $_.MaxNegativeTtl
                MaxTtl = $_.MaxTtl
                GatheredFrom = $Computer
            }
        }
    }
}
function Get-WinDnsServerDiagnostics {
    [CmdLetBinding()]
    param([string] $ComputerName)
    $DnsServerDiagnostics = Get-DnsServerDiagnostics -ComputerName $ComputerName
    foreach ($_ in $DnsServerDiagnostics) {
        [PSCustomObject] @{FilterIPAddressList = $_.FilterIPAddressList
            Answers = $_.Answers
            EnableLogFileRollover = $_.EnableLogFileRollover
            EnableLoggingForLocalLookupEvent = $_.EnableLoggingForLocalLookupEvent
            EnableLoggingForPluginDllEvent = $_.EnableLoggingForPluginDllEvent
            EnableLoggingForRecursiveLookupEvent = $_.EnableLoggingForRecursiveLookupEvent
            EnableLoggingForRemoteServerEvent = $_.EnableLoggingForRemoteServerEvent
            EnableLoggingForServerStartStopEvent = $_.EnableLoggingForServerStartStopEvent
            EnableLoggingForTombstoneEvent = $_.EnableLoggingForTombstoneEvent
            EnableLoggingForZoneDataWriteEvent = $_.EnableLoggingForZoneDataWriteEvent
            EnableLoggingForZoneLoadingEvent = $_.EnableLoggingForZoneLoadingEvent
            EnableLoggingToFile = $_.EnableLoggingToFile
            EventLogLevel = $_.EventLogLevel
            FullPackets = $_.FullPackets
            LogFilePath = $_.LogFilePath
            MaxMBFileSize = $_.MaxMBFileSize
            Notifications = $_.Notifications
            Queries = $_.Queries
            QuestionTransactions = $_.QuestionTransactions
            ReceivePackets = $_.ReceivePackets
            SaveLogsToPersistentStorage = $_.SaveLogsToPersistentStorage
            SendPackets = $_.SendPackets
            TcpPackets = $_.TcpPackets
            UdpPackets = $_.UdpPackets
            UnmatchedResponse = $_.UnmatchedResponse
            Update = $_.Update
            UseSystemEventLog = $_.UseSystemEventLog
            WriteThrough = $_.WriteThrough
            GatheredFrom = $ComputerName
        }
    }
}
function Get-WinDnsServerDirectoryPartition {
    [CmdLetBinding()]
    param([string] $ComputerName,
        [string] $Splitter)
    $DnsServerDirectoryPartition = Get-DnsServerDirectoryPartition -ComputerName $ComputerName
    foreach ($_ in $DnsServerDirectoryPartition) {
        [PSCustomObject] @{DirectoryPartitionName = $_.DirectoryPartitionName
            CrossReferenceDistinguishedName = $_.CrossReferenceDistinguishedName
            DirectoryPartitionDistinguishedName = $_.DirectoryPartitionDistinguishedName
            Flags = $_.Flags
            Replica = if ($Splitter -ne '') { $_.Replica -join $Splitter } else { $_.Replica }
            State = $_.State
            ZoneCount = $_.ZoneCount
            GatheredFrom = $ComputerName
        }
    }
}
function Get-WinDnsServerDsSetting {
    [CmdLetBinding()]
    param([string] $ComputerName)
    $DnsServerDsSetting = Get-DnsServerDsSetting -ComputerName $ComputerName
    foreach ($_ in $DnsServerDsSetting) {
        [PSCustomObject] @{DirectoryPartitionAutoEnlistInterval = $_.DirectoryPartitionAutoEnlistInterval
            LazyUpdateInterval = $_.LazyUpdateInterval
            MinimumBackgroundLoadThreads = $_.MinimumBackgroundLoadThreads
            RemoteReplicationDelay = $_.RemoteReplicationDelay
            TombstoneInterval = $_.TombstoneInterval
            GatheredFrom = $ComputerName
        }
    }
}
function Get-WinDnsServerEDns {
    [CmdLetBinding()]
    param([string] $ComputerName)
    $DnsServerDsSetting = Get-DnsServerEDns -ComputerName $ComputerName
    foreach ($_ in $DnsServerDsSetting) {
        [PSCustomObject] @{CacheTimeout = $_.CacheTimeout
            EnableProbes = $_.EnableProbes
            EnableReception = $_.EnableReception
            GatheredFrom = $ComputerName
        }
    }
}
function Get-WinDnsServerGlobalNameZone {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN)
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    foreach ($Computer in $ComputerName) {
        $DnsServerGlobalNameZone = Get-DnsServerGlobalNameZone -ComputerName $Computer
        foreach ($_ in $DnsServerGlobalNameZone) {
            [PSCustomObject] @{AlwaysQueryServer = $_.AlwaysQueryServer
                BlockUpdates = $_.BlockUpdates
                Enable = $_.Enable
                EnableEDnsProbes = $_.EnableEDnsProbes
                GlobalOverLocal = $_.GlobalOverLocal
                PreferAaaa = $_.PreferAaaa
                SendTimeout = $_.SendTimeout
                ServerQueryInterval = $_.ServerQueryInterval
                GatheredFrom = $Computer
            }
        }
    }
}
function Get-WinDnsServerGlobalQueryBlockList {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN,
        [switch] $Formatted,
        [string] $Splitter = ', ')
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    foreach ($Computer in $ComputerName) {
        $ServerGlobalQueryBlockList = Get-DnsServerGlobalQueryBlockList -ComputerName $Computer
        foreach ($_ in $ServerGlobalQueryBlockList) {
            if ($Formatted) {
                [PSCustomObject] @{Enable = $_.Enable
                    List = $_.List -join $Splitter
                    GatheredFrom = $Computer
                }
            } else {
                [PSCustomObject] @{Enable = $_.Enable
                    List = $_.List
                    GatheredFrom = $Computer
                }
            }
        }
    }
}
function Get-WinDnsServerRecursion {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN)
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    foreach ($Computer in $ComputerName) {
        $DnsServerRecursion = Get-DnsServerRecursion -ComputerName $Computer
        foreach ($_ in $DnsServerRecursion) {
            [PSCustomObject] @{AdditionalTimeout = $_.AdditionalTimeout
                Enable = $_.Enable
                RetryInterval = $_.RetryInterval
                SecureResponse = $_.SecureResponse
                Timeout = $_.Timeout
                GatheredFrom = $Computer
            }
        }
    }
}
function Get-WinDnsServerRecursionScope {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN)
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    foreach ($Computer in $ComputerName) {
        $DnsServerRecursionScope = Get-DnsServerRecursionScope -ComputerName $Computer
        foreach ($_ in $DnsServerRecursionScope) {
            [PSCustomObject] @{Name = $_.Name
                Forwarder = $_.Forwarder
                EnableRecursion = $_.EnableRecursion
                GatheredFrom = $Computer
            }
        }
    }
}
function Get-WinDnsServerResponseRateLimiting {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN)
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    foreach ($Computer in $ComputerName) {
        $DnsServerResponseRateLimiting = Get-DnsServerResponseRateLimiting -ComputerName $Computer
        foreach ($_ in $DnsServerResponseRateLimiting) {
            [PSCustomObject] @{ResponsesPerSec = $_.ResponsesPerSec
                ErrorsPerSec = $_.ErrorsPerSec
                WindowInSec = $_.WindowInSec
                IPv4PrefixLength = $_.IPv4PrefixLength
                IPv6PrefixLength = $_.IPv6PrefixLength
                LeakRate = $_.LeakRate
                TruncateRate = $_.TruncateRate
                MaximumResponsesPerWindow = $_.MaximumResponsesPerWindow
                Mode = $_.Mode
                GatheredFrom = $Computer
            }
        }
    }
}
function Get-WinDnsServerSettings {
    [CmdLetBinding()]
    param([string] $ComputerName)
    $DnsServerSetting = Get-DnsServerSetting -ComputerName $ComputerName -All
    foreach ($_ in $DnsServerSetting) {
        [PSCustomObject] @{AllIPAddress = $_.AllIPAddress
            ListeningIPAddress = $_.ListeningIPAddress
            BuildNumber = $_.BuildNumber
            ComputerName = $_.ComputerName
            EnableDnsSec = $_.EnableDnsSec
            EnableIPv6 = $_.EnableIPv6
            IsReadOnlyDC = $_.IsReadOnlyDC
            MajorVersion = $_.MajorVersion
            MinorVersion = $_.MinorVersion
            GatheredFrom = $ComputerName
        }
    }
}
function Get-WinDnsServerVirtualizationInstance {
    [CmdLetBinding()]
    param([string] $ComputerName)
    $DnsServerVirtualizationInstance = Get-DnsServerVirtualizationInstance -ComputerName $ComputerName
    foreach ($_ in $DnsServerVirtualizationInstance) {
        [PSCustomObject] @{VirtualizationInstance = $_.VirtualizationInstance
            FriendlyName = $_.FriendlyName
            Description = $_.Description
            GatheredFrom = $ComputerName
        }
    }
}
function Get-WinDnsServerZones {
    [CmdLetBinding()]
    param([string[]] $ComputerName,
        [string] $Domain = $ENV:USERDNSDOMAIN,
        [switch] $ReverseLookupZone,
        [switch] $PrimaryZone,
        [string] $ZoneName)
    if ($Domain -and -not $ComputerName) { $ComputerName = (Get-ADDomainController -Filter * -Server $Domain).HostName }
    $ReadyZones = foreach ($Computer in $ComputerName) {
        if ($ZoneName) { $Zones = Get-DnsServerZone -ComputerName $Computer -Name $ZoneName } else { $Zones = Get-DnsServerZone -ComputerName $Computer }
        foreach ($_ in $Zones) {
            if ($_.ZoneType -eq 'Primary') {
                $ZoneAging = Get-DnsServerZoneAging -Name $_.ZoneName -ComputerName $Computer
                $AgingEnabled = $ZoneAging.AgingEnabled
                $AvailForScavengeTime = $ZoneAging.AvailForScavengeTime
                $RefreshInterval = $ZoneAging.RefreshInterval
                $NoRefreshInterval = $ZoneAging.NoRefreshInterval
                $ScavengeServers = $ZoneAging.ScavengeServers
            } else {
                $AgingEnabled = $null
                $AvailForScavengeTime = $null
                $RefreshInterval = $null
                $NoRefreshInterval = $null
                $ScavengeServers = $null
            }
            [PSCustomObject] @{'ZoneName' = $_.'ZoneName'
                'AgingEnabled' = $AgingEnabled
                'AvailForScavengeTime' = $AvailForScavengeTime
                'RefreshInterval' = $RefreshInterval
                'NoRefreshInterval' = $NoRefreshInterval
                'ScavengeServers' = $ScavengeServers
                'NotifyServers' = $_.'NotifyServers'
                'SecondaryServers' = $_.'SecondaryServers'
                'AllowedDcForNsRecordsAutoCreation' = $_.'AllowedDcForNsRecordsAutoCreation'
                'DistinguishedName' = $_.'DistinguishedName'
                'IsAutoCreated' = $_.'IsAutoCreated'
                'IsDsIntegrated' = $_.'IsDsIntegrated'
                'IsPaused' = $_.'IsPaused'
                'IsReadOnly' = $_.'IsReadOnly'
                'IsReverseLookupZone' = $_.'IsReverseLookupZone'
                'IsShutdown' = $_.'IsShutdown'
                'ZoneType' = $_.'ZoneType'
                'DirectoryPartitionName' = $_.'DirectoryPartitionName'
                'DynamicUpdate' = $_.'DynamicUpdate'
                'IgnorePolicies' = $_.'IgnorePolicies'
                'IsSigned' = $_.'IsSigned'
                'IsWinsEnabled' = $_.'IsWinsEnabled'
                'Notify' = $_.'Notify'
                'ReplicationScope' = $_.'ReplicationScope'
                'SecureSecondaries' = $_.'SecureSecondaries'
                'ZoneFile' = $_.'ZoneFile'
                'GatheredFrom' = $Computer
            }
        }
    }
    $Output = @(if ($ReverseLookupZone -and $PrimaryZone) { $ReadyZones | Where-Object { $_.IsReverseLookupZone -eq $true -and $_.ZoneType -eq 'Primary' } } elseif ($ReverseLookupZone) { $ReadyZones | Where-Object { $_.IsReverseLookupZone -eq $true } } elseif ($PrimaryZone) { $ReadyZones | Where-Object { $_.ZoneType -eq 'Primary' -and $_.IsReverseLookupZone -eq $false } } else { $ReadyZones })
    $Output
}
function Get-WinDnsInformation {
    [CmdLetBinding()]
    param([alias('ForestName')][string] $Forest,
        [string[]] $ExcludeDomains,
        [string[]] $ExcludeDomainControllers,
        [alias('Domain', 'Domains')][string[]] $IncludeDomains,
        [alias('DomainControllers', 'ComputerName')][string[]] $IncludeDomainControllers,
        [string] $Splitter,
        [System.Collections.IDictionary] $ExtendedForestInformation)
    if ($null -eq $TypesRequired) { }
    $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC -ExtendedForestInformation $ExtendedForestInformation
    $DNSServers = @{ }
    foreach ($Computer in $ForestInformation.ForestDomainControllers.HostName) {
        $Data = [ordered] @{ }
        $Data.ServerCache = Get-WinDnsServerCache -ComputerName $Computer
        $Data.ServerClientSubnets = Get-DnsServerClientSubnet -ComputerName $Computer
        $Data.ServerDiagnostics = Get-WinDnsServerDiagnostics -ComputerName $Computer
        $Data.ServerDirectoryPartition = Get-WinDnsServerDirectoryPartition -ComputerName $Computer -Splitter $Splitter
        $Data.ServerDsSetting = Get-WinDnsServerDsSetting -ComputerName $Computer
        $Data.ServerEdns = Get-WinDnsServerEDns -ComputerName $Computer
        $Data.ServerForwarder = Get-WinDnsServerForwarder -ComputerName $Computer -ExtendedForestInformation $ForestInformation -Formatted -Splitter $Splitter
        $Data.ServerGlobalNameZone = Get-WinDnsServerGlobalNameZone -ComputerName $Computer
        $Data.ServerGlobalQueryBlockList = Get-WinDnsServerGlobalQueryBlockList -ComputerName $Computer -Splitter $Splitter
        $Data.ServerRecursion = Get-WinDnsServerRecursion -ComputerName $Computer
        $Data.ServerRecursionScopes = Get-WinDnsServerRecursionScope -ComputerName $Computer
        $Data.ServerResponseRateLimiting = Get-WinDnsServerResponseRateLimiting -ComputerName $Computer
        $Data.ServerResponseRateLimitingExceptionlists = Get-DnsServerResponseRateLimitingExceptionlist -ComputerName $Computer
        $Data.ServerRootHint = Get-WinDnsRootHint -ComputerName $Computer
        $Data.ServerScavenging = Get-WinDnsServerScavenging -ComputerName $Computer
        $Data.ServerSetting = Get-WinDnsServerSettings -ComputerName $Computer
        $Data.VirtualizedServer = $DNSServer.VirtualizedServer
        $Data.VirtualizationInstance = Get-WinDnsServerVirtualizationInstance -ComputerName $Computer
        $DNSServers.$Computer = $Data
    }
    return $DNSServers
}
function Get-WinDnsServerForwarder {
    [CmdLetBinding()]
    param([alias('ForestName')][string] $Forest,
        [string[]] $ExcludeDomains,
        [string[]] $ExcludeDomainControllers,
        [alias('Domain', 'Domains')][string[]] $IncludeDomains,
        [alias('DomainControllers', 'ComputerName')][string[]] $IncludeDomainControllers,
        [switch] $Formatted,
        [string] $Splitter = ', ',
        [System.Collections.IDictionary] $ExtendedForestInformation)
    $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC -ExtendedForestInformation $ExtendedForestInformation
    foreach ($Computer in $ForestInformation.ForestDomainControllers) {
        try { $DnsServerForwarder = Get-DnsServerForwarder -ComputerName $Computer.HostName -ErrorAction Stop } catch {
            $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
            Write-Warning "Get-WinDnsServerForwarder - Error $ErrorMessage"
            continue
        }
        foreach ($_ in $DnsServerForwarder) {
            if ($Formatted) {
                [PSCustomObject] @{IPAddress = $_.IPAddress.IPAddressToString -join $Splitter
                    ReorderedIPAddress = $_.ReorderedIPAddress.IPAddressToString -join $Splitter
                    EnableReordering = $_.EnableReordering
                    Timeout = $_.Timeout
                    UseRootHint = $_.UseRootHint
                    ForwardersCount = ($_.IPAddress.IPAddressToString).Count
                    GatheredFrom = $Computer.HostName
                    GatheredDomain = $Computer.Domain
                }
            } else {
                [PSCustomObject] @{IPAddress = $_.IPAddress.IPAddressToString
                    ReorderedIPAddress = $_.ReorderedIPAddress.IPAddressToString
                    EnableReordering = $_.EnableReordering
                    Timeout = $_.Timeout
                    UseRootHint = $_.UseRootHint
                    ForwardersCount = ($_.IPAddress.IPAddressToString).Count
                    GatheredFrom = $Computer.HostName
                    GatheredDomain = $Computer.Domain
                }
            }
        }
    }
}
function Get-WinDnsServerScavenging {
    [CmdLetBinding()]
    param([alias('ForestName')][string] $Forest,
        [string[]] $ExcludeDomains,
        [string[]] $ExcludeDomainControllers,
        [alias('Domain', 'Domains')][string[]] $IncludeDomains,
        [alias('DomainControllers', 'ComputerName')][string[]] $IncludeDomainControllers,
        [switch] $SkipRODC,
        [Array] $GPOs,
        [System.Collections.IDictionary] $ExtendedForestInformation)
    $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC -ExtendedForestInformation $ExtendedForestInformation
    foreach ($Computer in $ForestInformation.ForestDomainControllers) {
        try { $DnsServerScavenging = Get-DnsServerScavenging -ComputerName $Computer.HostName -ErrorAction Stop } catch {
            [PSCustomObject] @{NoRefreshInterval = $null
                RefreshInterval = $null
                ScavengingInterval = $null
                ScavengingState = $null
                LastScavengeTime = $null
                GatheredFrom = $Computer.HostName
                GatheredDomain = $Computer.Domain
            }
            continue
        }
        foreach ($_ in $DnsServerScavenging) {
            [PSCustomObject] @{NoRefreshInterval = $_.NoRefreshInterval
                RefreshInterval = $_.RefreshInterval
                ScavengingInterval = $_.ScavengingInterval
                ScavengingState = $_.ScavengingState
                LastScavengeTime = $_.LastScavengeTime
                GatheredFrom = $Computer.HostName
                GatheredDomain = $Computer.Domain
            }
        }
    }
}
Export-ModuleMember -Function @('Get-WinDnsInformation', 'Get-WinDnsServerForwarder', 'Get-WinDnsServerScavenging') -Alias @()