Skip to content

Instantly share code, notes, and snippets.

@AceOfNitwits
Created August 25, 2020 13:47
Show Gist options
  • Select an option

  • Save AceOfNitwits/aafe78ef5181dfd745ebdf033678c3e2 to your computer and use it in GitHub Desktop.

Select an option

Save AceOfNitwits/aafe78ef5181dfd745ebdf033678c3e2 to your computer and use it in GitHub Desktop.
Monitor for DNS Changes with PowerShell
<#
.SYNOPSIS
Records and compares DNS entries, checking their expected values against their current values.
.DESCRIPTION
DNS entries are stored in XML files in the current path or the path specified by the -BasePath parameter.
When run with the -AddDomain parameter, performs DNS lookups for SOA, NS, MX, TXT, and A records, as well as an A record for the autodiscover host and both an A and CNAME for the www host. Query responses are saved in .XML files in the current path or the path specified by the -BasePath parameter.
When run with the -AddHost (and optional -QueryType) parameter, performs a DNS lookup for the specified host. Query responses are saved in .xml files in the current path or the path specified by the -BasePath parameter.
When run with the -RunComparison parameter, performs DNS lookups for all previously-generated XML files in the current path, or the path specified by the -BasePath parameter. Alerts to any discrepencies found.
.EXAMPLE
./Compare-DNS.ps1 -RunComparison
Compares previously-generated files in the current path against current DNS queries.
.EXAMPLE
./Compare-DNS.pst -AddDomain abc.com, xyz.com
Creates .xml files for the specified domains in the current folder.
.EXAMPLE
./Compare-DNS.pst -AddHost www.abc.com, autodiscover.abc.com -QueryType cname, a
Creates .xml files for the specified hosts and specified query types in the current folder.
.PARAMETER -RunComparison
Runs the comparison against the previously generated files in the current folder.
.PARAMETER -AddDomain
Performs lookups and creates files for the domain(s) specified by this parameter. Uses the current folder or the -BasePath parameter to determine when to put the files.
This parameter will also update existing files.
.PARAMETER -BasePath
Used to specify a non-default path for the .xml files.get
.PARAMETER -DnsServer
Specifies the DNS server to use for name resolution. Default will use the default server.
.PARAMETER -Pause
Require user to press Enter before the script will terminate. For use with Windows shortcut.
To use in a shortcut: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "& 'C:\Users\Username\My Documents\Scripts\Compare-DNS.ps1' -runComparison -Pause"
#>
Param(
[switch]$RunComparison=$false,
[string[]]$AddHost,
[string[]]$QueryType,
[string[]]$AddDomain,
[string]$BasePath = '.',
[string]$DNSServer,
[switch]$Pause
)
<#
Iterates through a folder of XML files that contain DNS query response objects.
Figures out what the original query that generated them was and compares the two.
#>
Function Test-Resolutions {
Get-ChildItem -Path $basePath -Filter "*.xml" | ForEach-Object { #Get the xml files and iterate through them.
Write-Progress "Checking $_" #Write the name of the file currently being processed.
$expectedResponse = Import-Clixml $_.FullName #Import the xml file so we can do an object comparison.
If($expectedResponse){ #There might be a blank file, so we need to handle that.
$queryName = $expectedResponse[0].Name #This gets the domain name
$queryType = $expectedResponse[0].QueryType #This gets the query type
# Create the parameter hash table to splat to the Resolve-DnsName cmdlet.
$resolutionParameters = @{
Name = $queryName;
Type = $queryType;
DnsOnly = $true;
NoHostsFile = $true;
}
# If the user selected a custom DNS server, add that to the hash table.
# We can't reliably get the default DNS server, so this is how we do a conditional parameter.
If($dnsserver){
$resolutionParameters += @{Server = $DNSServer}
}
$currentResponse = Resolve-DnsName @resolutionParameters #Run the original query that generated the file.
If(Compare-Object $expectedResponse $currentResponse -Property Name,NameAdministrator,NameExchange,Preference,IP4Address,Strings,IPAddress,PrimaryServer,NameHost){ #Compare the original file to the result of the new query. If there's a difference this will return something.
Write-Host "Difference Detected!!!" -BackgroundColor Red -ForegroundColor Black #Yikes! Something changed!
#Compare-Object $expectedResponse $currentResponse -Property Name,NameAdministrator,NameExchange,Preference,IP4Address,Strings,IPAddress,PrimaryServer,NameHost,Strings | FT
Write-Host "Expected response (from file $_, last modified on " $_.LastWriteTime ")" -ForegroundColor Yellow
$expectedResponse | Select-Object -Property Type,Name,NameAdministrator,NameExchange,Preference,IP4Address,Strings,IPAddress,PrimaryServer,NameHost # Format-Table #Show me what you expected to get.
Write-Host "Current Response:" -ForegroundColor Yellow
$currentResponse | Select-Object -Property Type,Name,NameAdministrator,NameExchange,Preference,IP4Address,Strings,IPAddress,PrimaryServer,NameHost # Format-Table #Now show me what you got.
}
}
}
}
<#
Accepts an array of domain names in the following format
domain1.com,domain2.com,domain3.com
Generates XML files with DNS responses returned from various queries.
#>
Function Add-Domain ($domainList) {
$myQueryTypes = ('soa', 'ns', 'mx', 'txt', 'a')
Add-Record $domainList $myQueryTypes
Foreach($domain in $domainList){
Add-Record "www.$domain" a, cname
Add-Record "autodiscover.$domain" cname
}
}
Function Add-Record ($hostList, $typeList) {
If(-not $typeList){ # No query types were provided.
$typeList = 'a' # Set the query type to 'a'.
}
Foreach($myHost in $hostList){
# The following lines reverse the components of the dns name so we can create a file name with the tld first.
$hostArray = $myHost.Split('.')
[array]::Reverse($hostArray)
$reverseHost = [string]::join('.',$hostArray)
foreach($type in $typeList){
# Create the parameter hash table to splat to the Resolve-DnsName cmdlet.
$resolutionParameters = @{
Name = $myHost;
Type = $type;
DnsOnly = $true;
NoHostsFile = $true;
ErrorAction = 'STOP'
}
# If the user selected a custom DNS server, add that to the hash table.
# We can't reliably get the default DNS server, so this is how we do a conditional parameter.
If($dnsserver){
$resolutionParameters += @{Server = $DNSServer}
}
Write-Progress "Querying $type record for $host."
try {
Resolve-DnsName @resolutionParameters | Export-Clixml -Path "$basePath\$reverseHost.$type.xml" #Generate the record file.
}
catch {
Write-Host "Could not resolve $type record for $myHost`: $_" -ForegroundColor Red
}
}
}
}
If ($RunComparison){Test-Resolutions}
If ($AddDomain){Add-Domain $AddDomain}
If ($AddHost){Add-Record $AddHost $QueryType}
If ($Pause){
Read-Host -Prompt "Press Enter to Continue"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment