DNSValidator.ps1

<#==============================================================================
          File Name : DNSvalidator.ps1
    Original Author : Kenneth C. Mazie (kcmjr AT kcmjr DOT com)
                       :
        Description : Detects DNS assigned to local system. Pulls all records from selected DNS server and performs
                    : both a ping and an NSlookup on the record. Records to Excel and/or screen. Use to validate
                    : existing DNS records.
                       :
              Notes : Normal operation is with no command line options.
                    :
  Optional arguments: -Debug $true (defaults to false). Sends email to debug address from config file.
                       : -UseExcel $false (defaults to true). Creates and emails an excel spreadsheet
                       : -Console $true (defaults to false). Displays runtime info on console
                       :
           Warnings : None
                       :
              Legal : Public Domain. Modify and redistribute freely. No rights reserved.
                       : SCRIPT PROVIDED "AS IS" WITHOUT WARRANTIES OR GUARANTEES OF
                       : ANY KIND. USE AT YOUR OWN RISK. NO TECHNICAL SUPPORT PROVIDED.
                      :
               Credits : Code snippets and/or ideas came from many sources including but
                      : not limited to the following:
                    :
     Last Update by : Kenneth C. Mazie
    Version History : v1.00 - 02-22-16 - Original
     Change History : v2.00 - 03-06-17 - Major rewrite. Fixed numerous bugs. Converted to PS objects.
                    : v2.01 - 05-17-17 - Never completed previous update. Working now.
                    : v2.02 - 08-07-17 - Fixed issue causing duplication of data between record types.
                    : v2.03 - 01-03-18 - Adjusted a script name variables to use script name as config file
                    : v2.04 - 05-29-18 - Added DNS commandlet to pull server list from local system.
                    : v2.41 - 05-29-18 - Corrected color issues on output HTML & Spreadsheet. Adjusted
                    : version number due to version issue with library
                    : v2.50 - 06-04-18 - corrected errors in debug output and result file naming.
                    :
#===============================================================================#>

<#PSScriptInfo
.VERSION 2.50
.GUID 6faf7da3-2c8c-4274-9ceb-fbbb275d62e4
.AUTHOR Kenneth C. Mazie (kcmjr AT kcmjr DOT com)
.DESCRIPTION
Detects DNS assigned to local system. Pulls all records from selected DNS server and performs
both a ping and an NSlookup on the record. Records to Excel and/or screen. Use to validate
existing DNS records.
#>

#requires -version 5.0

Param(
    [bool]$Debug = $False,
    [bool]$Console = $false,
    [bool]$UseExcel = $True,
    [bool]$SendEmail = $True,
    [bool]$InlineHTML = $False
    )
    
If ($Debug){$Script:Debug = $true}
If ($Console){$Script:Console = $true}
If ($UseExcel){$Script:UseExcel = $true}
If ($SendEmail){$Script:SendEmail = $true}
If ($InlineHTML){$Script:InlineHTML = $true}

#$Script:Debug = $true
#$Script:Console = $true

Clear-host
#$Script:DNSDomainName = (Get-ADDomain).DNSroot #--[ Detected below ]--
$ErrorActionPreference = "silentlycontinue"
$DateTime = Get-Date -Format MM-dd-yyyy_HHmmss 
$Script:ScriptName = ($MyInvocation.MyCommand.Name).split(".")[0] 
$Script:LogFile = $PSScriptRoot+"\"+$ScriptName+"_"+$DateTime+".log" 
$Script:ConfigFile = $PSScriptRoot+'\'+$Script:ScriptName+'.xml'
[string]$Script:FileName = $Script:ScriptName+'_'+$DateTime
$Script:FullFileName = $PSScriptRoot+"\"+$Script:FileName
$Script:ReportBody = ""
$Script:DNS_Entries = ""
$Script:HTMLData = ""
$Script:RowData = ""
$Script:ReportBody = ""
$Script:dnsrecord = ""
$Script:DNSIPAddress = ""
$Script:HostName = ""
$Script:DNSRecordTextRepresentation = ""
$Script:DNSRecordType = ""
$Script:Count = ""
$Script:Counter = ""
$Mode = ""
$Script:Excel = ""

$RecordTypes = @("CNAMEtype","Atype")                                         #--[ Change to alter what types of records are scanned ]--
#$RecordTypes = @("Atype")
#$RecordTypes = @("CNAMEtype")
#Get-WmiObject -Namespace root\MicrosoftDNS -List #--[ FYI only - This gets a list of all DNS name classes...

Function LoadConfiguration{         
    #--[ Read and load configuration file ]-------------------------------------
    If (!(Test-Path $Script:ConfigFile)){                                               #--[ Error out if configuration file doesn't exist ]--
          $Script:HTMLData = "MISSING CONFIG FILE. Script aborted."
        If ($Script:Log){Add-content -Path "$PSScriptRoot\debug.txt" -Value "MISSING CONFIG FILE. Script aborted."}
        Write-Host "CONFIGURATION FILE NOTE FOUND - EXITING" -ForegroundColor Red 
          break
    }Else{
        [xml]$Script:Configuration = Get-Content $Script:ConfigFile                     #--[ Read & Load XML ]--
        #$Script:DnsServer = $Script:Configuration.Settings.General.DnsServer #--[ Detected. See below ]--
        $Script:DnsDomain = $Script:Configuration.Settings.General.Domain
        $Script:DebugEmail = $Script:Configuration.Settings.Email.Debug 
        $Script:DebugTarget = $Script:Configuration.Settings.General.DebugTarget 
        $Script:eMailRecipient = $Script:Configuration.Settings.Email.To
        $Script:eMailFrom = $Script:Configuration.Settings.Email.From    
        $Script:eMailHTML = $Script:Configuration.Settings.Email.HTML
        $Script:eMailSubject = $Script:Configuration.Settings.Email.Subject
        $Script:SmtpServer = $Script:Configuration.Settings.Email.SmtpServer
        $Script:UserName = $Script:Configuration.Settings.Credentials.Username
        $Script:EncryptedPW = $Script:Configuration.Settings.Credentials.Password
        $Script:Base64String = $Script:Configuration.Settings.Credentials.Key
        $Script:ReportName = $Script:Configuration.Settings.General.ReportName
        $ByteArray = [System.Convert]::FromBase64String($Script:Base64String)
        $Script:Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Script:UserName, ($Script:EncryptedPW | ConvertTo-SecureString -Key $ByteArray)
        #$Script:Credential.password
    }
    
    #------------------------------------------------------------------------------------------
    #--[ NOTE: Sometime issues can result if an existing connection to the primary DNS host is present. ]--
    #--[ Future change may include auto detection and selection here. ]--
    $Script:DNS1 = (Get-DnsClientServerAddress -AddressFamily "IPv4").ServerAddresses[0]
    $Script:DNS2 = (Get-DnsClientServerAddress -AddressFamily "IPv4").ServerAddresses[1]
    $Script:DNSServer = $Script:DNS1
    #------------------------------------------------------------------------------------------

    If ($Script:Debug){
        Write-host "-- DEBUGGING INFO --" -ForegroundColor magenta 
        Write-host "DnsServer = "$Script:DnsServer -ForegroundColor Red 
        Write-host "Domain = "$Script:DNSDomain -ForegroundColor Red 
        Write-host "Debug email = "$Script:DebugEmail -ForegroundColor Red 
        Write-host "Debug target = "$Script:DebugTarget -ForegroundColor Red 
        Write-host "Subject = "$Script:eMailSubject -ForegroundColor Red     
        Write-host "EmailTo = "$Script:eMailRecipient -ForegroundColor Red 
        Write-host "EmailFrom = "$Script:eMailFrom -ForegroundColor Red 
        Write-host "SmtpServer = "$Script:SmtpServer -ForegroundColor Red 
        Write-host "HTML = "$Script:eMailHTML -ForegroundColor Red 
        Write-host "Username = "$Script:UserName -ForegroundColor Red 
        Write-host "Password = HIDDEN" -ForegroundColor Red #$Script:Password
        Write-host "Report Name = "$Script:ReportName -ForegroundColor Red 
    }    

    If ($Script:Log){
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "-- DEBUGGING INFO --"
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "vCenter(s) = $Script:vCenters"
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "Debug email = $Script:DebugEmail"
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "Debug target = $Script:DebugTarget"
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "Subject = $Script:Subject"
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "EmailTo = $Script:EmailTo "
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "SmtpServer = $Script:SmtpServer" 
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "HTML = $Script:EmailHTML"
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "Username = $Script:UserName "
        Add-content -Path "$PSScriptRoot\debug.txt" -Value "Password = $Script:Password "
    }
}

Function ConsoleColor {  #--[ Detect console color and adjust accordingly ]------------------------------
    If ((Get-Host).UI.RawUI.BackgroundColor -eq "White"){
        $Script:FgGreen = "DarkGreen"
        $Script:FgRed = "DarkRed"
        $Script:FgYellow = "DarkCyan"
        $Script:FgBlue = "DarkCyan"
        $Script:FgCyan = "DarkCyan"
        $Script:FgMagenta = "DarkCyan"
        $Script:FgGray = "DarkGray"
        $Script:FgText = "Black"
    }Else{
        $Script:FgGreen = "Green"
        $Script:FgRed = "Red"
        $Script:FgYellow = "Yellow"
        $Script:FgBlue = "Blue"
        $Script:FgCyan = "Cyan"
        $Script:FgMagenta = "Magenta"
        $Script:FgGray = "Gray"
        $Script:FgText = "White"
    }
}

Function SendEmail {
    $Script:Email = $null
    $Script:Email = New-Object System.Net.Mail.MailMessage
    $Script:Email.From = $Script:EmailFrom
    If ($Script:InlineHTML){
        $Script:Email.Body = $Script:ReportBody    
    }Else{
        $Script:Email.Body = 'Please see attached reports.<br><br>Script "'+$Script:ScriptName+'" executed at "'+$DateTime+'" from server "'+$Env:ComputerName+'".' #$Script:ReportBody
    }    
    $Script:Email.IsBodyHtml = $Script:eMailHTML
    If ($Script:Debug){
           $Script:Email.To.Add($Script:DebugEmail)                                                   #--[ Debug destination email address ]--
        If ($Script:Console){write-host "`n--[ DEBUG Email sent ]--" -ForegroundColor $Script:FgGreen}
    }Else{    
            $Script:Email.To.Add($Script:eMailRecipient)                                              #--[ Destination email address ]--
        If ($Script:Console){write-host "`n--[ Email sent ]--" -ForegroundColor $Script:FgGreen}
    }
    $Script:Email.Subject = $Script:eMailSubject
    
    If ($Script:UseExcel){ $Script:Email.Attachments.Add($Script:FullFileName+'.xlsx')}            #--[ Attach spreadsheet if using Excel ]--
    $Script:Email.Attachments.Add($Script:FullFileName+'.html')                                  #--[ Attach HTML file ]--
    
    $smtp = new-object Net.Mail.SmtpClient($Script:SMTPServer)
    If ($Script:SendEmail){$smtp.Send($Script:Email)}
}

Function PingHost ($PingTarget){
    $Script:PingResult = ""
    
    #$filter = 'Address="' + $Script:IPAddress + '"' #\
    #$Script:TargetResponse = Get-WmiObject -Class Win32_PingStatus -Filter $filter #--[ Alternates ]--
    #$Script:TargetResponse = Get-WmiObject -Class Win32_PingStatus -Filter ('Address="' + $Script:IPAddress + '"') #/
    
    $Script:TargetResponse = get-wmiobject -Query "select * from win32_pingstatus where Address = '$PingTarget'" -ErrorAction Stop 
    
    $Code = $Script:TargetResponse.statuscode
    switch ($Code) {
        0 { $Script:PingResult = 'Successfull' }
        11001 { $Script:PingResult = 'Buffer too small' }
        11002 { $Script:PingResult = 'Destination net unreachable' }
        11003 { $Script:PingResult = "Destination Host Unreachable "}
        11004 {    $Script:PingResult = "Destination Protocol Unreachable"}
        11005 { $Script:PingResult = "Destination Port Unreachable "}
        11006 { $Script:PingResult = "No Resources "}
        11007 { $Script:PingResult = "Bad Option "}
        11008 { $Script:PingResult = "Hardware Error "}
        11009 { $Script:PingResult = "Packet Too Big "}
        11010 { $Script:PingResult = "Request Timed Out" }
        11011 { $Script:PingResult = "Bad Request "}
        11012 { $Script:PingResult = "Bad Route "}
        11013 { $Script:PingResult = "TimeToLive Expired Transit "}
        11014 { $Script:PingResult = "TimeToLive Expired Reassembly" }
        11015 { $Script:PingResult = "Parameter Problem "}
        11016 { $Script:PingResult = "Source Quench "}
        11017 { $Script:PingResult = "Option Too Big "}
        11018 { $Script:PingResult = "Bad Destination "}
        11032 { $Script:PingResult = "Negotiating IPSEC" }
        11050 { $Script:PingResult = "General Failure "}
        default { $Script:PingResult = 'Failed.' }
    }
}

Function PrepSheet ($Mode){
    [int]$Script:Row = 1
    If ($Script:Excel -eq "" ){
        $Script:Excel = New-Object -ComObject Excel.Application                 #--[ Create excel COM object if not already created ]--
        $Script:Excel.Visible = $true #false #--[ Make it visible ]--
        #$Script:Excel.DisplayAlerts = $False
        $Script:Workbook = $Script:Excel.Workbooks.Add()                        #--[ Add a workbook ]--
        $Script:WorkSheet = $Script:Workbook.Worksheets.Item(1)                 #--[ Connect to first worksheet to rename and make active ]--
        $Script:WorkSheet.Name = $Mode.Split('t')[0]+' Records'                 #--[ Rename it ]--
        $Script:WorkSheet.Activate() | Out-Null                                 #--[ Make it active ]--
        
        $Iterations = $Script:Workbook.Worksheets.Count                         #--[ Remove all but first worksheet ]--
        $TempEAP = $ErrorActionPreference
        $ErrorActionPreference = "silentlycontinue"
        While ($Iterations -gt 1){
            $Script:Workbook.Worksheets.Item($i).Delete()
            $Iterations--
        }
        $ErrorActionPreference = $TempEAP
    }Else{
        $Script:WorkSheet = $Script:Workbook.Worksheets.Add()                   #--[ Add a worksheet ]--
        $Script:WorkSheet.Name = $Mode.Split('t')[0]+' Records'                 #--[ Rename it ]--
        $Script:WorkSheet.Activate() | Out-Null                                 #--[ Make it active ]--
    }

    $Script:Column = 1
    $range = $Script:WorkSheet.Range(("A1"),("P1")) #"+[int]$Script:Row),("P"+[int]$Script:Row))
    $range.Style = 'Title'
    $range.font.bold = $True
    $range.Interior.ColorIndex = 56
    $range.Font.ColorIndex = 44
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Hostname"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "DNS Domain"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Record Type"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "DNS Server"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "DNS Record Owner"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "DNS Record Primary"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "DNS Record IP"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Ping Target"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Ping Result"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "NSLookup Server"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Fwd Lookup Target"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Fwd Lookup Result"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Rev Lookup Target"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "Rev Lookup Result"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "DNS Alias(s)"
    $Script:WorkSheet.cells.Item(1,$Script:Column++) = "NsLookup Mismatch"
    $Range1 = $Script:WorkSheet.Range('a1:p1')
    $Range1.font.bold = $True
    
    1..4 | ForEach {
           $Range1.Borders.Item($_).LineStyle = 1
           $Range1.Borders.Item($_).Weight = 4
    }
    $Resize = $Script:WorkSheet.UsedRange
       [Void]$Resize.EntireColumn.AutoFit()
    $Script:Row++
}

#--End of Functions ]-----------------------------------------------------------

#==[ Main Process ]=============================================================
ConsoleColor 
LoadConfiguration

#--[ Add header to html output file ]--
$Script:ReportBody = @() 
$Script:ReportBody += '
<style type="text/css">
    table.myTable { border:5px solid black;border-collapse:collapse;}
    table.myTable td { border:2px solid black;padding:5px;white-space:nowrap;}
    table.myTable tr { border:2px solid black;padding:5px;white-space:nowrap;}
    table.myTable th { border:2px solid black;padding:5px;background:#949494;white-space:nowrap;}
    table.bottomBorder { border-collapse:collapse; }
    table.bottomBorder td, table.bottomBorder th { border-bottom:1px dotted black;padding:5px; }
    tr.noBorder td {border:0}
    td.auto { border:2px solid black;padding:5px;white-space:nowrap;}
</style>'


$Script:ReportBody += 
'<table class="myTable">
    <tr class="noBorder"><td colspan=16><center><h1>- '
 + $Script:ReportName + ' -</h1></td></tr>
    <tr class="noBorder"><td colspan=16><center>The following report displays DNS records, the data associated with them, and separate ping, NSlookup, and reverse lookup results.</td></tr>
    <tr class="noBorder"><td colspan=16></tr>
'


ForEach ($Type in $RecordTypes){
    If ($Script:UseExcel){PrepSheet $Type}
    $Script:DNS_Entries = Get-WmiObject -namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_$Type" -ComputerName $Script:DNSServer -Filter "DomainName = '$Script:DnsDomain'" -Credential $Script:Credential
    $Script:HTMLData = ""
    $Script:HTMLData = @() 

    If ($Script:DNS_Entries -ne $null){
          If ($Script:Console){write-host `n`n"------[ Mode ="($Type.Split("t")[0])"Records ]------"`n -ForegroundColor Gray}
        $Script:Counter = 1
        $Script:Count = $Script:DNS_Entries.count

        #--[ Add header to html output file ]--
        $Script:HTMLData += '<tr class="myTable"><th>Hostname</th><th>DNS Domain</th><th>Record Type</th><th>DNS Server</th><th>DNS Record Owner</th><th>DNS Record Primary</th><th>DNS Record IP</th><th>Ping Target</th><th>Ping Result</th><th>NSLookup Server</th><th>Fwd Lookup Target</th><th>Fwd Lookup Result</th><th>Rev Lookup Target</th><th>Rev Lookup Result</th><th>DNS Alias(s)</th><th>NsLookup Mismatch</th></tr>'
        #--[ HTML row Settings ]----------------------------------------------------
        $BGColor = "#dfdfdf"                                                    #--[ Grey default cell background ]--
        $BGColorRed = "#ff0000"                                                 #--[ Red background for alerts ]--
        $BGColorOra = "#ff9900"                                                 #--[ Orange background for alerts ]--
        $BGColorYel = "#ffd900"                                                 #--[ Yellow background for alerts ]--
        $FGColor = "#000000"                                                    #--[ Black default cell foreground ]--
        $Script:RowData += '<tr>'                                                #--[ Start table row ]--
    
        foreach ($Script:DNSRecord in $Script:DNS_Entries ){ 
            $Script:DNSRecordObj = New-Object -TypeName PSObject
            $Script:Column = 1    
            If ($Script:Console){write-host "`n--[ $Script:Counter of $Script:Count ]--------------------------------------" }
            Try{
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSServerName -Value $Script:DNSRecord.DnsServerName
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSContainerName -Value $Script:DNSRecord.ContainerName
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSDomainName -Value ([string]::Join(".",($Script:DNSRecord.OwnerName.Split(".")[1],$Script:DNSRecord.OwnerName.Split(".")[2])))
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSRecordTextRepresentation -Value $Script:DNSRecord.TextRepresentation 
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSRecordType -Value $Script:DNSRecord.TextRepresentation.Split(" ")[2]
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSRecordData -Value $Script:DNSRecord.RecordData
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSIPAddress -Value $Script:DNSRecord.IPAddress
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSOwnerName -Value $Script:DNSRecord.OwnerName
            If ($Type -eq "Atype"){ 
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSPrimaryName -Value "N/A (CNAME only)"
            }Else{    
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSPrimaryName -Value $Script:DNSRecord.PrimaryName
            }
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name HostName -Value $Script:DNSRecord.OwnerName.split(".")[0]    
            }Catch{
                If ($Script:Console){Write-host "Exception 1: "$_.Exception.Message -ForegroundColor Yellow}
            }    
            
            If ($Script:Debug){
                Write-Host "--[ Debug 1 ]--------------------" -ForegroundColor Cyan 
                $Script:DNSRecord
                Write-Host "--[ Debug 2 ]--------------------" -ForegroundColor Cyan 
                $Script:DNSRecordObj
                Write-Host "--[ Debug 3 ]--------------------" -ForegroundColor Cyan 
            }    
                
            #-[ Ping Connectivity Test ]----------------------------------------
            If ($Type -eq "Atype"){
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name PingTarget -Value $Script:DNSRecord.IPAddress 
            }Else{
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name PingTarget -Value $Script:DNSRecord.OwnerName
            }
            PingHost $Script:DNSRecordObj.PingTarget        
            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name PingResult -Value $Script:PingResult
        
            #--[ Forward Lookup - Nslookup ]---------------------------------------------------------
            If ($Script:HostName -eq $Script:DNSServerName){# -or ($Type -eq "Atype")){
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "Not Applicable" -Force 
            }Else{
                #--[ Forward Lookup ]-------------------------------------------
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookup_Target -Value $Script:DNSRecordObj.HostName #+"."+$Script:DNSDomainName) -Force
                Try{
                    $HostLookup = (nslookup $Script:DNSRecordObj.NSLookup_Target )
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Raw -Value $HostLookup
                }Catch{
                    If ($Script:Console){Write-host "Exception 2: "$_.Exception.Message -ForegroundColor Yellow}
                }
                If ($Type -eq "Atype"){            
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSIPAddress -Value $Script:DNSRecordObj.DNSIPAddress -Force 
                }Else{
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSIPAddress -Value "N/A (A Reconds Only)" -Force 
                }
                Try{
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Server -Value ($HostLookup[0] -split â€˜:’)[1].Trim()
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Server_IP -Value ($HostLookup[1] -split â€˜:’)[1].Trim()
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Target -Value ($HostLookup[3] -split â€˜:’)[1].Trim()
                    If ($Script:DNSRecordObj.PingResult -eq "Failed."){
                        Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Target_IP -Value "Unavailable"
                    }Else{
                        Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Target_IP -Value ($HostLookup[4] -split â€˜:’)[1].Trim()
                    }
                    If (($Type -eq "CNAMEtype")){
                        Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Target_Alias -Value ($HostLookup[5] -split â€˜:’)[1].Trim()
                    }Else{
                        Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Target_Alias -Value "Not Applicable"
                    }
                }Catch{
                    If ($Script:DNSRecordObj.DNSDomainName -ne "int."){
                        If ($Script:Console){Write-host "Exception 3: "$_.Exception.Message -ForegroundColor Yellow }
                    }
                }    
                
                #--[ Reverse Lookup ]-------------------------------------------
                If ($Script:PingResult -like "*Failed*"){
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookupResult_Raw -Value "Unavailable"
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_DNS_Host -Value "Unavailable"
                       Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_DNS_IP -Value "Unavailable"
                     Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_Target -Value "Unavailable"
                       Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_Target_IP -Value "Unavailable"    
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name NSLookupResult_Target_Alias -Value "Unavailable" -Force 
                    Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "Unavailable" -Force
                }Else{
                    Try{
                        #$HostLookup = (nslookup $Script:DNSRecordObj.NSLookupResult_Target ) #--[ Doesn't work ]--
                        $HostLookup = (ping -a $Script:DNSRecordObj.NSLookupResult_Target -n 1 )
                    }Catch{
                        If ($Script:Console){Write-host "Exception 4: "$_.Exception.Message -ForegroundColor Yellow }
                    }
                    If ($Script:DNSRecordObj.DNSDomainName -ne "int."){  
                        Try{
                            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_Target -Value (($HostLookup[1]).Split(" ")[1])
                               Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_Target_IP -Value ((($HostLookup[1].split(" ")[2]).TrimStart("[")).TrimEnd("]"))
                        }Catch{
                            If ($Script:Console){Write-host "Exception 5: "$_.Exception.Message -ForegroundColor Yellow }
                        }            
                    }Else{
                        Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_Target -Value ""
                           Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name RevLookup_Target_IP -Value ""
                    }

                    #If ($Type -eq "Atype"){
                        If ($NS_DNS_Host -ne $RevLookup_DNS_Host){
                            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "DNS Host Mismatch"
                        }ElseIf($NS_DNS_IP -ne $RevLookup_DNS_IP){
                            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "DNS IP Mismatch"
                        }ElseIf ($NS_Target_Host -ne $RevLookup_Target_Host){
                            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "Hostname Mismatch"
                        }ElseIf ($NS_Target_IP -ne $RevLookup_Target_IP){
                            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "IP Mismatch"
                        }Else{
                            Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "None"
                        }    
                    #}Else{
                    # Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "N/A (A Records Only)" -Force
                    #}
                }
            }

            #--[ Displays full dump of RecordData object for debugging ]--------
            If ($Script:Debug){  
                Write-Host "--[ Debug 4 ]--------------------" -ForegroundColor Cyan 
                $Script:DNSRecord
                Write-Host "--[ Debug 5 ]--------------------" -ForegroundColor Cyan 
                $Script:DNSRecordObj
                Write-Host "--[ Debug 6 ]--------------------" -ForegroundColor Cyan 
            }    
            
            #--[ Some cleanup ]-------------------------------------------------
            If ($Script:DNSRecordObj.DNSDomainName -eq "int."){   
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Hostname -Value "" -Force 
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name DNSPrimaryName -Value "" -Force 
                Add-Member -InputObject $Script:DNSRecordObj -MemberType NoteProperty -Name Mismatch -Value "" -Force 
            }
                        
            #--[ Data to console display ]--------------------------------------
            If ($Script:Console){ 
                #write-host "Target Record ="$Script:DNSRecordObj.DNSPrimaryName.Split(".")[0] -ForegroundColor $Script:FgYellow
                write-host "Target Record ="$Script:DNSRecordObj.Hostname -ForegroundColor $Script:FgYellow 
                write-host "DNS Domain ="$Script:DNSRecordObj.DNSDomainName -ForegroundColor $Script:FgCyan
                write-host "DNS Record Type ="$Script:DNSRecordObj.DNSRecordType -ForegroundColor $Script:FgCyan
                write-host "DNS Server ="$Script:DNSRecordObj.DNSServerName -ForegroundColor $Script:FgCyan 
                write-host "DNS Record OwnerName ="$Script:DNSRecordObj.DNSOwnerName -ForegroundColor $Script:FgCyan    
                write-host "DNS Record PrimaryName ="$Script:DNSRecordObj.DNSPrimaryName -ForegroundColor $Script:FgCyan     
                write-host "DNS Record IP Address ="$Script:DNSRecordObj.DNSIPAddress -ForegroundColor $Script:FgCyan
                write-host "Ping Target ="$Script:DNSRecordObj.PingTarget -ForegroundColor $Script:FgCyan
            }
            #--[ Data for Excel attachment ]----------------------------------------
            If($Script:UseExcel){
                $Script:WorkSheet.cells.Item([int]$Script:Row,1) = $Script:DNSRecordObj.HostName
                $Script:WorkSheet.cells.Item([int]$Script:Row,2) = $Script:DNSRecordObj.DNSDomainName
                $Script:WorkSheet.cells.Item([int]$Script:Row,3) = $Script:DNSRecordObj.DNSRecordType
                $Script:WorkSheet.cells.Item([int]$Script:Row,4) = $Script:DNSRecordObj.DNSServerName    
                $Script:WorkSheet.cells.Item([int]$Script:Row,5) = $Script:DNSRecordObj.DNSOwnerName 
                $Script:WorkSheet.cells.Item([int]$Script:Row,6) = $Script:DNSRecordObj.DNSPrimaryName            
                $Script:WorkSheet.cells.Item([int]$Script:Row,7) = $Script:DNSRecordObj.DNSIPAddress
                $Script:WorkSheet.cells.Item([int]$Script:Row,8) = $Script:DNSRecordObj.PingTarget
            }    
            #--[ Data for email report ]--------------------------------------------
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.HostName + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.DNSDomainName + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.DNSRecordType + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.DNSServerName + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.DNSOwnerName + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.DNSPrimaryName + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.DNSIPAddress + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.PingTarget + '</td>'
            
            If ($Script:Console){write-host "Ping Result = " -ForegroundColor Cyan -NoNewline }
            If ($Script:PingResult -like "*success*"){
                If ($Script:Console){write-host $Script:DNSRecordObj.PingResult -ForegroundColor $Script:FgGreen     }
                If ($Script:UseExcel){$Script:WorkSheet.cells.item([int]$Script:Row,9).font.ColorIndex = 10    }
                $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=#008000>' + $Script:DNSRecordObj.PingResult + '</td>'
            }Else{
                  If ($Script:Console){write-host $Script:DNSRecordObj.PingResult -ForegroundColor $Script:FgRed    }
                If ($Script:UseExcel){
                    $Script:WorkSheet.cells.item([int]$Script:Row,9).font.ColorIndex = 3
                      $Script:WorkSheet.cells.item([int]$Script:Row,9).font.bold = $true 
                }
                $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=#800000>' + $Script:DNSRecordObj.PingResult + '</td>'
            }
            If ($Script:UseExcel){$Script:WorkSheet.cells.Item([int]$Script:Row,9) = $Script:DNSRecordObj.PingResult }
                    
            If ($Script:Console){
                Write-Host "NSLookup Server ="$Script:DNSRecordObj.NSLookupResult_Server -ForegroundColor Cyan 
                Write-Host "NSLookup Target ="$Script:DNSRecordObj.NSLookupResult_Target -ForegroundColor Cyan 
                Write-Host "NSLookup Target IP ="$Script:DNSRecordObj.NSLookupResult_Target_IP -ForegroundColor Cyan                 
                #Write-Host "Reverse Lookup Raw Result ="$Script:DNSRecordObj.RevLookupResult_Raw -ForegroundColor Cyan
                Write-Host "Reverse Lookup Target ="$Script:DNSRecordObj.RevLookup_Target -ForegroundColor Cyan                
                Write-Host "Reverse Lookup Target IP ="$Script:DNSRecordObj.RevLookup_Target_IP -ForegroundColor Cyan 
            }
            If($Script:UseExcel){
                $Script:WorkSheet.cells.Item([int]$Script:Row,10) = $Script:DNSRecordObj.NSLookupResult_Server    
                $Script:WorkSheet.cells.Item([int]$Script:Row,11) = $Script:DNSRecordObj.NSLookupResult_Target
                $Script:WorkSheet.cells.Item([int]$Script:Row,12) = $Script:DNSRecordObj.NSLookupResult_Target_IP
                $Script:WorkSheet.cells.Item([int]$Script:Row,13) = $Script:DNSRecordObj.RevLookup_Target_IP
            # If ($NS_Target_IP -ne $RevLookup_Target_IP){
            # $Script:WorkSheet.cells.item([int]$Script:Row,12).font.ColorIndex = 3
            # $Script:WorkSheet.cells.item([int]$Script:Row,12).font.bold = $true
            # $Script:WorkSheet.cells.item([int]$Script:Row,13).font.ColorIndex = 3
            # $Script:WorkSheet.cells.item([int]$Script:Row,13).font.bold = $true
            # }
                $Script:WorkSheet.cells.Item([int]$Script:Row,14) = $Script:DNSRecordObj.RevLookup_Target
            }        

            #--[ Data for email report ]--------------------------------------------
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.NSLookupResult_Server + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.NSLookupResult_Target + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.NSLookupResult_Target_IP + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.RevLookup_Target_IP + '</td>'
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.RevLookup_Target + '</td>'
            
            If ($Script:Console){write-host "DNS Alias(s) = " -ForegroundColor Cyan -NoNewline }
            If ($Script:DNSRecordObj.DNSRecordType -eq "CNAME"){
                If ($Script:Console){write-host $Script:DNSRecordObj.NSLookupResult_Target_Alias -ForegroundColor $Script:FgCyan}
                If($Script:UseExcel){$Script:WorkSheet.cells.Item([int]$Script:Row,15) = $Script:DNSRecordObj.NSLookupResult_Target_Alias }
                $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.NSLookupResult_Target_Alias + '</td>'
            }Else{
                If ($Script:DNSRecordObj.DNSDomainName -eq "int."){  
                    If ($Script:Console){write-host $Script:DNSRecordObj.DNSOwnerName -ForegroundColor $Script:FgCyan }
                    If($Script:UseExcel){$Script:WorkSheet.cells.Item([int]$Script:Row,15) = $Script:DNSRecordObj.DNSOwnerName}
                    $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>' + $Script:DNSRecordObj.DNSOwnerName + '</td>'
                }Else{            
                    If ($Script:Console){write-host "N/A (CNAME Only)" -ForegroundColor $Script:FgCyan }
                    If($Script:UseExcel){$Script:WorkSheet.cells.Item([int]$Script:Row,15) = "N/A (CNAME Only)"}
                    $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $FGColor + '>N/A (CNAME Only)</td>'
                }
            }
                
            If ($Script:Console){Write-Host "Lookup Mismatch = " -NoNewline -ForegroundColor Cyan }
                
            If ($Script:DNSRecordObj.Mismatch -like "*None*"){
                If ($Script:Console){write-host $Script:DNSRecordObj.Mismatch -ForegroundColor Green}
                If($Script:UseExcel){
                    $Script:WorkSheet.cells.Item([int]$Script:Row,16) = $Script:DNSRecordObj.Mismatch 
                    $Script:WorkSheet.cells.item([int]$Script:Row,16).font.ColorIndex = 10
                }
                $Color = "green"
            }ElseIf (($Script:DNSRecordObj.Mismatch -like "*Applicable*") -or ($Script:DNSRecordObj.Mismatch -like "*Unavailable*")){    
                If ($Script:Console){write-host $Script:DNSRecordObj.Mismatch -ForegroundColor Cyan}
                If($Script:UseExcel){$Script:WorkSheet.cells.Item([int]$Script:Row,16) = $Script:DNSRecordObj.Mismatch }
                $Color = $FGColor
            }Else{    
                If ($Script:Console){write-host $Script:DNSRecordObj.Mismatch -ForegroundColor red}
                If ($Script:UseExcel){    
                    $Script:WorkSheet.cells.Item([int]$Script:Row,16) = $Script:DNSRecordObj.Mismatch
                }
                $Color = "red"
            }
            
            $Script:RowData += '<td class="myTable" bgcolor=' + $BGColor + '><font color=' + $Color + '>' + $Script:DNSRecordObj.Mismatch + '</font></td>'
    
            If($Script:UseExcel){
                $dataRange = $Script:WorkSheet.Range(("A{0}" -f [int]$Script:Row),("P{0}" -f [int]$Script:Row))
                1..4 | ForEach {
                    $dataRange.Borders.Item($_).LineStyle = 1
                    $dataRange.Borders.Item($_).Weight = 2
                }
            }    
            $Script:RowData += '</tr>'
            $Script:Row++        
            $Script:Counter++
            if($Counter%5 -and $Script:UseExcel){
                  $Resize = $Script:WorkSheet.UsedRange
                  [Void]$Resize.EntireColumn.AutoFit()
            }
        }    
        $Script:HTMLData += $Script:RowData
        $Script:RowData.Clear()
        $Script:RowData = $Null
        $Script:Row++
    }Else{
        $Script:HTMLData += '<tr class="noBorder"><td colspan=16><center>No records detected.</td></tr>'
    }

    #--[ Populate data ]--
    $Script:ReportBody += $Script:HTMLData
    $Script:ReportBody += '<tr class="noBorder"><td colspan=16></tr>'
    $Script:HTMLData.Clear() 
    $Script:HTMLData = $Null    
}

#--[ Cleanup ]------------------------------------------------------------------
If ($Script:Console){
    Write-Host `n"Script Name = "$Script:ScriptName".ps1"
    Write-Host "Result File Name ="$Script:FullFileName".xlsx" 
}    

If ($Script:UseExcel){
    $dataRange = $Script:WorkSheet.Range(("A1"),("P1"))
    1..4 | ForEach {
        $dataRange.Borders.Item($_).LineStyle = 1
        $dataRange.Borders.Item($_).Weight = 4
    }
      $Resize = $Script:WorkSheet.UsedRange
      [Void]$Resize.EntireColumn.AutoFit()
      $Script:Workbook.SaveAs("$Script:FullFileName.xlsx")
      $Script:Workbook.Saved = $true 
      $Script:Workbook.Close() 
      $Script:Excel.quit()
}
$Script:ReportBody += '</table><br><br>'
$Script:ReportBody | Out-File "$Script:FullFileName.html"
SendEmail 

#--[ Remove all but the ten most recent output files ]--------------------------
If (!($Script:Debug)){
    Get-ChildItem -Path "$PSScriptRoot\*.html" | Where-Object { -not $_.PsIsContainer } | Sort-Object -Descending -Property LastTimeWrite | Select-Object -Skip 10 | Remove-Item -ErrorAction:SilentlyContinue      
    Get-ChildItem -Path "$PSScriptRoot\*.xlsx" | Where-Object { -not $_.PsIsContainer } | Sort-Object -Descending -Property LastTimeWrite | Select-Object -Skip 10 | Remove-Item -ErrorAction:SilentlyContinue     
}

[GC]::Collect() 

Write-Host "--- COMPLETED ---" -ForegroundColor Red 


#--[ XML Config file example. Keep in folder with script. ]--------------------------------------------------------------
<#
<!-- Settings & Configuration File -->
<Settings>
    <General>
        <ReportName>DNS Record Validation Report</ReportName>
        <DebugTarget>testdnshost</DebugTarget>
        <Domain>mydomain.com</Domain>
    </General>
    <Email>
        <From>WeeklyReports@mydomain.com</From>
        <To>myemail@mydomain.com</To>
        <Debug>debugemail@mydomain.com</Debug>
        <Subject>Weekly DNS Record Validation Report</Subject>
        <HTML>$true</HTML>
        <SmtpServer>10.10.15.5</SmtpServer>
    </Email>
    <Credentials>
        <UserName>domain\serviceaccount</UserName>
        <Password>76492d1116743foAeQAAFEAPQA9AHwAYwAzADL6/AWnHbuTeJ7IX0AEcAaAAzQA9AHwAYwAWnHbuTeJAeQA0AEAHwAYwAzADL6/AWnHbuTeJ7IXN0IOAw0423413b16050aAwAeQA0AEcAaAB1AFEAcAaAB1N0IOZgBkAGYAZAA=</Password>
        <Key>kdB1AFEAPQA9PQA9AHwAYwAWnHbuTeJ7IXN0IObie8mE=</Key>
    </Credentials>
</Settings>
 
 
 
#>