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() }
        }
        foreach ($Domain in $ForestInformation.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] $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) {
            $QueryServer = $Findings['QueryServers'][$Domain]['HostName'][0]
            [Array] $AllDC = try {
                try { $DomainControllers = Get-ADDomainController -Filter $Filter -Server $QueryServer -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'] = @{}
            $Findings['DomainsExtendedNetBIOS'] = @{}
            foreach ($DomainEx in $Findings['Domains']) {
                try {
                    $Findings['DomainsExtended'][$DomainEx] = Get-ADDomain -Server $Findings['QueryServers'][$DomainEx].HostName[0] | ForEach-Object { [ordered] @{AllowedDNSSuffixes = $_.AllowedDNSSuffixes | ForEach-Object -Process { $_ }
                            ChildDomains = $_.ChildDomains | ForEach-Object -Process { $_ }
                            ComputersContainer = $_.ComputersContainer
                            DeletedObjectsContainer = $_.DeletedObjectsContainer
                            DistinguishedName = $_.DistinguishedName
                            DNSRoot = $_.DNSRoot
                            DomainControllersContainer = $_.DomainControllersContainer
                            DomainMode = $_.DomainMode
                            DomainSID = $_.DomainSID.Value
                            ForeignSecurityPrincipalsContainer = $_.ForeignSecurityPrincipalsContainer
                            Forest = $_.Forest
                            InfrastructureMaster = $_.InfrastructureMaster
                            LastLogonReplicationInterval = $_.LastLogonReplicationInterval
                            LinkedGroupPolicyObjects = $_.LinkedGroupPolicyObjects | ForEach-Object -Process { $_ }
                            LostAndFoundContainer = $_.LostAndFoundContainer
                            ManagedBy = $_.ManagedBy
                            Name = $_.Name
                            NetBIOSName = $_.NetBIOSName
                            ObjectClass = $_.ObjectClass
                            ObjectGUID = $_.ObjectGUID
                            ParentDomain = $_.ParentDomain
                            PDCEmulator = $_.PDCEmulator
                            PublicKeyRequiredPasswordRolling = $_.PublicKeyRequiredPasswordRolling | ForEach-Object -Process { $_ }
                            QuotasContainer = $_.QuotasContainer
                            ReadOnlyReplicaDirectoryServers = $_.ReadOnlyReplicaDirectoryServers | ForEach-Object -Process { $_ }
                            ReplicaDirectoryServers = $_.ReplicaDirectoryServers | ForEach-Object -Process { $_ }
                            RIDMaster = $_.RIDMaster
                            SubordinateReferences = $_.SubordinateReferences | ForEach-Object -Process { $_ }
                            SystemsContainer = $_.SystemsContainer
                            UsersContainer = $_.UsersContainer
                        } }
                    $NetBios = $Findings['DomainsExtended'][$DomainEx]['NetBIOSName']
                    $Findings['DomainsExtendedNetBIOS'][$NetBios] = $Findings['DomainsExtended'][$DomainEx]
                } catch {
                    Write-Warning "Get-WinADForestDetails - Error gathering Domain Information for domain $DomainEx - $($_.Exception.Message)"
                    continue
                }
            }
        }
        if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress }
        $Findings
    } else {
        $Findings = Copy-DictionaryManual -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.DomainsExtended.Keys) {
            if ($_ -notin $Findings.Domains) {
                $Findings.DomainsExtended.Remove($_)
                $NetBiosName = $Findings.DomainsExtended.$_.'NetBIOSName'
                if ($NetBiosName) { $Findings.DomainsExtendedNetBIOS.Remove($NetBiosName) }
            }
        }
        [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 Remove-EmptyValue {
    [alias('Remove-EmptyValues')]
    [CmdletBinding()]
    param([alias('Splat', 'IDictionary')][Parameter(Mandatory)][System.Collections.IDictionary] $Hashtable,
        [string[]] $ExcludeParameter,
        [switch] $Recursive,
        [int] $Rerun)
    foreach ($Key in [string[]] $Hashtable.Keys) { if ($Key -notin $ExcludeParameter) { if ($Recursive) { if ($Hashtable[$Key] -is [System.Collections.IDictionary]) { if ($Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } else { Remove-EmptyValue -Hashtable $Hashtable[$Key] -Recursive:$Recursive } } else { if ($null -eq $Hashtable[$Key] -or ($Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') -or ($Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0)) { $Hashtable.Remove($Key) } } } else { if ($null -eq $Hashtable[$Key] -or ($Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') -or ($Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0)) { $Hashtable.Remove($Key) } } } }
    if ($Rerun) { for ($i = 0; $i -lt $Rerun; $i++) { Remove-EmptyValue -Hashtable $Hashtable -Recursive:$Recursive } }
}
function ConvertTo-OperatingSystem {
    <#
    .SYNOPSIS
    Allows easy conversion of OperatingSystem, Operating System Version to proper Windows 10 naming based on WMI or AD
 
    .DESCRIPTION
    Allows easy conversion of OperatingSystem, Operating System Version to proper Windows 10 naming based on WMI or AD
 
    .PARAMETER OperatingSystem
    Operating System as returned by Active Directory
 
    .PARAMETER OperatingSystemVersion
    Operating System Version as returned by Active Directory
 
    .EXAMPLE
    $Computers = Get-ADComputer -Filter * -Properties OperatingSystem, OperatingSystemVersion | ForEach-Object {
        $OPS = ConvertTo-OperatingSystem -OperatingSystem $_.OperatingSystem -OperatingSystemVersion $_.OperatingSystemVersion
        Add-Member -MemberType NoteProperty -Name 'OperatingSystemTranslated' -Value $OPS -InputObject $_ -Force
        $_
    }
    $Computers | Select-Object DNS*, Name, SamAccountName, Enabled, OperatingSystem*, DistinguishedName | Format-Table
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([string] $OperatingSystem,
        [string] $OperatingSystemVersion)
    if ($OperatingSystem -like '*Windows 10*') {
        $Systems = @{'10.0 (19042)' = 'Windows 10 Insider Preview Build 19042.421 (20H2)'
            '10.0 (19041)' = 'Windows 10 2004'
            '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.19042' = 'Windows 10 Insider Preview Build 19042.421 (20H2)'
            '10.0.19041' = 'Windows 10 2004'
            '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 Copy-DictionaryManual {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Dictionary)
    $clone = @{}
    foreach ($Key in $Dictionary.Keys) {
        $value = $Dictionary.$Key
        $clonedValue = switch ($Dictionary.$Key) {
            { $null -eq $_ } {
                $null
                continue
            }
            { $_ -is [System.Collections.IDictionary] } {
                Copy-DictionaryManual -Dictionary $_
                continue
            }
            { $type = $_.GetType()
                $type.IsPrimitive -or $type.IsValueType -or $_ -is [string] } {
                $_
                continue
            }
            default { $_ | Select-Object -Property * }
        }
        if ($value -is [System.Collections.IList]) { $clone[$Key] = @($clonedValue) } else { $clone[$Key] = $clonedValue }
    }
    $clone
}
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-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
            }
        }
    }
}
function Get-WinDnsServerZones {
    [CmdLetBinding()]
    param([alias('ForestName')][string] $Forest,
        [string[]] $ExcludeDomains,
        [string[]] $ExcludeDomainControllers,
        [alias('Domain', 'Domains')][string[]] $IncludeDomains,
        [alias('DomainControllers')][string[]] $IncludeDomainControllers,
        [switch] $SkipRODC,
        [System.Collections.IDictionary] $ExtendedForestInformation,
        [switch] $ReverseLookupZone,
        [switch] $PrimaryZone,
        [switch] $Forwarder,
        [string] $ZoneName)
    $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC -ExtendedForestInformation $ExtendedForestInformation
    foreach ($Domain in $ForestInformation.Domains) {
        foreach ($Computer in $ForestInformation['DomainDomainControllers'][$Domain]) {
            $getDnsServerZoneSplat = @{ComputerName = $Computer.HostName
                Name = $ZoneName
            }
            Remove-EmptyValue -Hashtable $getDnsServerZoneSplat
            $Zones = Get-DnsServerZone @getDnsServerZoneSplat -ErrorAction SilentlyContinue
            foreach ($_ in $Zones) {
                if ($ZoneName) { if ($ZoneName -ne $_.ZoneName) { continue } }
                if ($_.ZoneType -eq 'Primary') {
                    $ZoneAging = Get-DnsServerZoneAging -Name $_.ZoneName -ComputerName $Computer.HostName
                    $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
                }
                if ($Forwarder) { if ($_.ZoneType -ne 'Forwarder') { continue } } elseif ($ReverseLookupZone -and $PrimaryZone) { if ($_.IsReverseLookupZone -ne $true -or $_.ZoneType -ne 'Primary') { continue } } elseif ($ReverseLookupZone) { if ($_.IsReverseLookupZone -ne $true) { continue } } elseif ($PrimaryZone) { if ($_.ZoneType -ne 'Primary' -or $_.IsReverseLookupZone -ne $false) { continue } }
                [PSCustomObject] @{'ZoneName' = $_.'ZoneName'
                    'ZoneType' = $_.'ZoneType'
                    'IsPDC' = $Computer.IsPDC
                    'AgingEnabled' = $AgingEnabled
                    'AvailForScavengeTime' = $AvailForScavengeTime
                    'RefreshInterval' = $RefreshInterval
                    'NoRefreshInterval' = $NoRefreshInterval
                    'ScavengeServers' = $ScavengeServers
                    'MasterServers' = $_.MasterServers
                    'NotifyServers' = $_.'NotifyServers'
                    'SecondaryServers' = $_.'SecondaryServers'
                    'AllowedDcForNsRecordsAutoCreation' = $_.'AllowedDcForNsRecordsAutoCreation'
                    'DistinguishedName' = $_.'DistinguishedName'
                    'IsAutoCreated' = $_.'IsAutoCreated'
                    'IsDsIntegrated' = $_.'IsDsIntegrated'
                    'IsPaused' = $_.'IsPaused'
                    'IsReadOnly' = $_.'IsReadOnly'
                    'IsReverseLookupZone' = $_.'IsReverseLookupZone'
                    'IsShutdown' = $_.'IsShutdown'
                    'DirectoryPartitionName' = $_.'DirectoryPartitionName'
                    'DynamicUpdate' = $_.'DynamicUpdate'
                    'IgnorePolicies' = $_.'IgnorePolicies'
                    'IsSigned' = $_.'IsSigned'
                    'IsWinsEnabled' = $_.'IsWinsEnabled'
                    'Notify' = $_.'Notify'
                    'ReplicationScope' = $_.'ReplicationScope'
                    'SecureSecondaries' = $_.'SecureSecondaries'
                    'ZoneFile' = $_.'ZoneFile'
                    'GatheredFrom' = $Computer.HostName
                    'GatheredDomain' = $Domain
                }
            }
        }
    }
}
Export-ModuleMember -Function @('Get-WinDnsInformation', 'Get-WinDnsServerForwarder', 'Get-WinDnsServerScavenging', 'Get-WinDnsServerZones') -Alias @()
# SIG # Begin signature block
# MIIdSQYJKoZIhvcNAQcCoIIdOjCCHTYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUDWTqQtTUkOHks9SYc8GYvQbk
# 20qgghhnMIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0B
# AQUFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk
# IElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQsw
# CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
# ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg
# Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg
# +XESpa7cJpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lT
# XDGEKvYPmDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5
# a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g
# 0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1
# roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
# GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G
# A1UdDgQWBBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLL
# gjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3
# cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmr
# EthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+
# fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5Q
# Z7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu
# 838fYxAe+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw
# 8jCCBP4wggPmoAMCAQICEA1CSuC+Ooj/YEAhzhQA8N0wDQYJKoZIhvcNAQELBQAw
# cjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
# d3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVk
# IElEIFRpbWVzdGFtcGluZyBDQTAeFw0yMTAxMDEwMDAwMDBaFw0zMTAxMDYwMDAw
# MDBaMEgxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEgMB4G
# A1UEAxMXRGlnaUNlcnQgVGltZXN0YW1wIDIwMjEwggEiMA0GCSqGSIb3DQEBAQUA
# A4IBDwAwggEKAoIBAQDC5mGEZ8WK9Q0IpEXKY2tR1zoRQr0KdXVNlLQMULUmEP4d
# yG+RawyW5xpcSO9E5b+bYc0VkWJauP9nC5xj/TZqgfop+N0rcIXeAhjzeG28ffnH
# bQk9vmp2h+mKvfiEXR52yeTGdnY6U9HR01o2j8aj4S8bOrdh1nPsTm0zinxdRS1L
# sVDmQTo3VobckyON91Al6GTm3dOPL1e1hyDrDo4s1SPa9E14RuMDgzEpSlwMMYpK
# jIjF9zBa+RSvFV9sQ0kJ/SYjU/aNY+gaq1uxHTDCm2mCtNv8VlS8H6GHq756Wwog
# L0sJyZWnjbL61mOLTqVyHO6fegFz+BnW/g1JhL0BAgMBAAGjggG4MIIBtDAOBgNV
# HQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
# CDBBBgNVHSAEOjA4MDYGCWCGSAGG/WwHATApMCcGCCsGAQUFBwIBFhtodHRwOi8v
# d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHwYDVR0jBBgwFoAU9LbhIB3+Ka7S5GGlsqIl
# ssgXNW4wHQYDVR0OBBYEFDZEho6kurBmvrwoLR1ENt3janq8MHEGA1UdHwRqMGgw
# MqAwoC6GLGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMu
# Y3JsMDKgMKAuhixodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVk
# LXRzLmNybDCBhQYIKwYBBQUHAQEEeTB3MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
# cC5kaWdpY2VydC5jb20wTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jYWNlcnRzLmRpZ2lj
# ZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURUaW1lc3RhbXBpbmdDQS5jcnQw
# DQYJKoZIhvcNAQELBQADggEBAEgc3LXpmiO85xrnIA6OZ0b9QnJRdAojR6OrktIl
# xHBZvhSg5SeBpU0UFRkHefDRBMOG2Tu9/kQCZk3taaQP9rhwz2Lo9VFKeHk2eie3
# 8+dSn5On7UOee+e03UEiifuHokYDTvz0/rdkd2NfI1Jpg4L6GlPtkMyNoRdzDfTz
# ZTlwS/Oc1np72gy8PTLQG8v1Yfx1CAB2vIEO+MDhXM/EEXLnG2RJ2CKadRVC9S0y
# OIHa9GCiurRS+1zgYSQlT7LfySmoc0NR2r1j1h9bm/cuG08THfdKDXF+l7f0P4Tr
# weOjSaH6zqe/Vs+6WXZhiV9+p7SOZ3j5NpjhyyjaW4emii8wggUwMIIEGKADAgEC
# AhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVT
# MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
# b20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEw
# MjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV
# BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEi
# MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7
# RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p
# 0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj
# 6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grk
# V7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHy
# DxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMB
# AAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAT
# BgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGG
# GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2Nh
# Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCB
# gQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lD
# ZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNl
# cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgG
# CmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
# Y29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1
# DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQEL
# BQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q
# 3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/
# kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dc
# IFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6
# dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT
# +hKUGIUukpHqaGxEMrJmoecYpJpkUe8wggUxMIIEGaADAgECAhAKoSXW1jIbfkHk
# Bdo2l8IVMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxE
# aWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMT
# G0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xNjAxMDcxMjAwMDBaFw0z
# MTAxMDcxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0
# IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEB
# AQUAA4IBDwAwggEKAoIBAQC90DLuS82Pf92puoKZxTlUKFe2I0rEDgdFM1EQfdD5
# fU1ofue2oPSNs4jkl79jIZCYvxO8V9PD4X4I1moUADj3Lh477sym9jJZ/l9lP+Cb
# 6+NGRwYaVX4LJ37AovWg4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuFfAnT7l3ImgtU
# 46gJcWvgzyIQD3XPcXJOCq3fQDpct1HhoXkUxk0kIzBdvOw8YGqsLwfM/fDqR9mI
# UF79Zm5WYScpiYRR5oLnRlD9lCosp+R1PrqYD4R/nzEU1q3V8mTLex4F0IQZchfx
# FwbvPc3WTe8GQv2iUypPhR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGjggHOMIIByjAd
# BgNVHQ4EFgQU9LbhIB3+Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgwFoAUReuir/SS
# y4IxLVGLp6chnfNtyA8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC
# AYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUF
# BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6
# Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5j
# cnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwUAYDVR0gBEkw
# RzA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj
# ZXJ0LmNvbS9DUFMwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4IBAQBxlRLp
# UYdWac3v3dp8qmN6s3jPBjdAhO9LhL/KzwMC/cWnww4gQiyvd/MrHwwhWiq3BTQd
# aq6Z+CeiZr8JqmDfdqQ6kw/4stHYfBli6F6CJR7Euhx7LCHi1lssFDVDBGiy23UC
# 4HLHmNY8ZOUfSBAYX4k4YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcSR3CzddWThZN+
# tpJn+1Nhiaj1a5bA9FhpDXzIAbG5KHW3mWOFIoxhynmUfln8jA/jb7UBJrZspe6H
# USHkWGCbugwtK22ixH67xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZmXbZ0e/VWMyIv
# IjayS6JKldj1po5SMIIFPTCCBCWgAwIBAgIQBNXcH0jqydhSALrNmpsqpzANBgkq
# hkiG9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT
# SEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDYyNjAwMDAwMFoX
# DTIzMDcwNzEyMDAwMFowejELMAkGA1UEBhMCUEwxEjAQBgNVBAgMCcWabMSFc2tp
# ZTERMA8GA1UEBxMIS2F0b3dpY2UxITAfBgNVBAoMGFByemVteXPFgmF3IEvFgnlz
# IEVWT1RFQzEhMB8GA1UEAwwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7KB3iyBrhkLUbbFe9qxhKKPBYqD
# Bqlnr3AtpZplkiVjpi9dMZCchSeT5ODsShPuZCIxJp5I86uf8ibo3vi2S9F9AlfF
# jVye3dTz/9TmCuGH8JQt13ozf9niHecwKrstDVhVprgxi5v0XxY51c7zgMA2g1Ub
# +3tii0vi/OpmKXdL2keNqJ2neQ5cYly/GsI8CREUEq9SZijbdA8VrRF3SoDdsWGf
# 3tZZzO6nWn3TLYKQ5/bw5U445u/V80QSoykszHRivTj+H4s8ABiforhi0i76beA6
# Ea41zcH4zJuAp48B4UhjgRDNuq8IzLWK4dlvqrqCBHKqsnrF6BmBrv+BXQIDAQAB
# o4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0O
# BBYEFBixNSfoHFAgJk4JkDQLFLRNlJRmMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUE
# DDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2Ny
# bDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUw
# QzA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl
# cnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcw
# AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8v
# Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNp
# Z25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAmr1s
# z4lsLARi4wG1eg0B8fVJFowtect7SnJUrp6XRnUG0/GI1wXiLIeow1UPiI6uDMsR
# XPHUF/+xjJw8SfIbwava2eXu7UoZKNh6dfgshcJmo0QNAJ5PIyy02/3fXjbUREHI
# NrTCvPVbPmV6kx4Kpd7KJrCo7ED18H/XTqWJHXa8va3MYLrbJetXpaEPpb6zk+l8
# Rj9yG4jBVRhenUBUUj3CLaWDSBpOA/+sx8/XB9W9opYfYGb+1TmbCkhUg7TB3gD6
# o6ESJre+fcnZnPVAPESmstwsT17caZ0bn7zETKlNHbc1q+Em9kyBjaQRcEQoQQNp
# ezQug9ufqExx6lHYDjGCBEwwggRIAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYD
# VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAv
# BgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EC
# EATV3B9I6snYUgC6zZqbKqcwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAI
# oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB
# CzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFA91vRCbM/Hk/3QpZcpk
# q/lD7iszMA0GCSqGSIb3DQEBAQUABIIBAIEE0o2F18DZ0/As+NnGzO2YeO2Ut8Ec
# k8MCnOk2JCVw62SilZY+njXWkkAJqu2G1XYyNpVsDDP4Df0w1ZNMz8Qa+H87gTfn
# 5YJ4awP59NqFTOnyrOba+pnuILZyGuutwjZgd4zFAnQ+oKeRnACErfrDgHqhaTU3
# g1q0mI/YlhZlsTF1wCTBFfugtFEU0pOFq5NBKVpfYZBkJCkraJSdom5oV3CY7h92
# jGV195YhqRE4vTDy1H8R7VDy9dYuTbdlvBnhRECx1gZL2qYTCH/o235w2yQFvy8q
# mezKjYLWTzAfFe+7ywqpTv9Qt9f/veAUbnKjzGO28zzK3vgXErWx6mChggIgMIIC
# HAYJKoZIhvcNAQkGMYICDTCCAgkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNV
# BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G
# A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQ
# DUJK4L46iP9gQCHOFADw3TAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqG
# SIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjEwMTE5MDgwNDAyWjAjBgkqhkiG9w0B
# CQQxFgQUX6bVIvmYylK9A//QroQ9Ce9vigkwDQYJKoZIhvcNAQEBBQAEggEATV3K
# klKx76D95YEByEhPScnt+otyzZ34YD0tZ8C0wBHiVkbB2KR3KBL9vzFw1uoevrUB
# gyAc0sAxpzmFebZvSfQhMaAW3/V4JAsEyC4SG3kgWDhMeXAWayKdBMDensPzFQAB
# okDK6NaaMca6suEiX228PpTWYmnuv57VztuEzQwyGJhYruHIeXa6pxK0VTtY7Bfi
# HnZ0SiAQD9AxM+vySPQ+3kKCO/uZDJH6SuEkSpWJJQumqhzxeYDYo/+62vD8FuT1
# fL68yafD7+o8qyHQt13GSVU729Ppm4yFgsR5OwRanFKmabAitnZX0PVot/HFWSwP
# UzQMjkyzRcM5P8S89w==
# SIG # End signature block