0

Get SPF Record Changes using PowerShell

I recently had to do an audit to log any changes that were made to public DNS records and I found that there was nothing out there that really that suited my needs. Therefore, I wrote my own Powershell script to Get SPF record changes using PowerShell.
 

I should note that this will check against a file that is previously written to disk. If there are any changes between the before file and the current file, an email will be sent to the person/DL you specified. It would be best to set this as a scheduled task within a relatively short period like a day. If you want a narrower timeframe, you can set it every hour so you can act on it pretty quickly if the change was not expected.

What is an SPF Record and why you should keep yours updated

Before we start getting into what and when the changes were made, let’s take a second to explain exactly what an SPF record is and why it is so important to mail security and mail flow.
 

An SPF (Sender Policy Framework) record is a DNS TXT record that tells you which mail servers are allowed to send email on your domain’s behalf. Adding an SPF record to your domain can aid in detecting and preventing non authorized users from sending email messages with fake “From” addresses.
 

Keeping an up-to-date SPF record coupled with the implementation of DMARC and DKIM can really help you fight against people sending email as your domain and help reduce spoofing attempts.

How the PowerShell script works

The way the Powershell script works is pretty simple. Basically, it will check any domain’s public SPF records using the Google DNS API and log that information to a JSON file. If there was a change the next time the script runs, it will send an email to alert you of the change.
 

This is kind of a poor man’s monitoring system if you will, but it will definitely get the job done. Since the script is calling public APIs, you can check any domain that comes to mind, you will just need to add it to the DomainList array.
 

Validate an SPF Record

One thing I struggled to figure out was how to validate an SPF record using Powershell, therefore, I opted to go this route. There are several awesome tools like MXToolbox SPF Checker that you can validate your SPF record manually through a browswer.
SPFRecord
 

The idea is that when you change your record, you validate it using one of these online tools to know it’s in a well known state. If one of your colleagues happens to have rights to change the records and doesn’t know what they’re doing, this will at least notify you that it was changed. It will also tell you exactly what records have been removed and what records have been added for each domain.
 

Since you’re not updating SPF records everyday (hopefully), doing a manual check every so often wouldn’t be too cumbersome and at the very least you now have a record of when all changes were made. Unfortunately since this is public info, there’s no way to see who made the change so you’ll have to investigate internally.

Get SPF Record Changes using PowerShell

Now moving on to the Powershell script to get SPF record changes for any domain that happens to cross your mind. Just be sure to change the domain list (line #18 on desktop) and the email notification information (line 128-131 on desktop)

<#
.SYNOPSIS
    This will check for any changes to a domain's SPF record using a previous export as reference.

.NOTES
    Name: Get-SPFRecordChange
    Author: [email protected]
    Version: 1.0
    DateCreated: 2022-Jan-10

.LINK
    https://thesysadminchannel.com/get-spf-record-changes-using-powershell -
#>

$WarningPreference = "SilentlyContinue"

$ExportPath = "$Home\SPFCheck"
$DomainList = 'domain1.com', 'domain2.com'

$SPFRecord = foreach ($Domain in $DomainList) {
    Invoke-RestMethod -Uri "https://dns.google.com/resolve?name=$Domain&type=TXT" | select -ExpandProperty Answer | Where-Object {$_.data -like 'v=spf*'}
}
$SPFRecord   | ConvertTo-Json -Depth 5 | Out-File $ExportPath\Audit_RecordSPFCurrent.json

if (-not (Test-Path "$ExportPath\Audit_RecordSPFBefore.json")) {
    Rename-Item $ExportPath\Audit_RecordSPFCurrent.json -NewName Audit_RecordSPFBefore.json
    $SPFRecord   | ConvertTo-Json -Depth 5 | Out-File $ExportPath\Audit_RecordSPFCurrent.json
}
#To compare apples to apples, let us import from export
$SPFBefore  = Get-Content "$ExportPath\Audit_RecordSPFBefore.json" | ConvertFrom-Json
$SPFCurrent = Get-Content "$ExportPath\Audit_RecordSPFCurrent.json" | ConvertFrom-Json

$ChangesOutput = foreach ($Domain in $DomainList) {
    $SPF1 = $SPFBefore | Where-Object {$_.Name -match $Domain}
    $SPF2 = $SPFCurrent | Where-Object {$_.Name -match $Domain}

    $SPFArray1 = $SPF1.data.Split(' ') -as [array]
    $SPFArray2 = $SPF2.data.Split(' ') -as [array]

    $CompareSPF = Compare-Object $SPFArray1 $SPFArray2

    if ($CompareSPF) {
        $Removed = ($CompareSPF | Where-Object {$_.SideIndicator -eq '<='} | select -ExpandProperty InputObject) -as [array]
        $Added   = ($CompareSPF | Where-Object {$_.SideIndicator -eq '=>'} | select -ExpandProperty InputObject) -as [array]

        $i = 0
        $TotalAdded = $Added.Count
        $TotalRemoved = $Removed.Count

        if  ($TotalAdded -gt $TotalRemoved) {
            $StopCount = $TotalAdded

            if ($null -eq $Removed) {
                do {
                    [PSCustomObject]@{
                        Domain  = $Domain
                        Added   = $Added[$i]
                        Removed = $null
                    }
                    $i++
                } until ($i -eq $StopCount)
            } else {
                do {
                    [PSCustomObject]@{
                        Domain  = $Domain
                        Added   = $Added[$i]
                        Removed = $Removed[$i]
                    }
                    $i++
                } until ($i -eq $StopCount)
            }

        } else {
            $StopCount = $TotalRemoved

            if ($null -eq $Added) {
                do {
                    [PSCustomObject]@{
                        Domain  = $Domain
                        Added   = $null
                        Removed = $Removed[$i]
                    }
                    $i++
                } until ($i -eq $StopCount)
            } else {
                do {
                    [PSCustomObject]@{
                        Domain  = $Domain
                        Added   = $Added[$i]
                        Removed = $Removed[$i]
                    }
                    $i++
                } until ($i -eq $StopCount)
            }
        }
    }
}


#$LastWriteTime = Get-ChildItem "$ExportPath\Audit_RecordSPFBefore.json" | select -ExpandProperty LastWriteTime
if ($ChangesOutput) {
    $Body = ""
    $Body = $Body + "<p>The following changes have been made to the Domain SPF Records</p>"
    $Body = $Body + '<table style="border-collapse: collapse"; border="1px solid black"; cellpadding="5px" >'
    $Body = $Body + "<tbody>"
    $Body = $Body + "<tr>"
    $Body = $Body + "<td><strong>Domain</strong></td>"
    $Body = $Body + "<td><strong>RecordsAdded</strong></td>"
    $Body = $Body + "<td><strong>RecordsRemoved</strong></td>"
    $Body = $Body + "</tr>"


    foreach ($Change in $ChangesOutput) {
        $Body = $Body + "<tr>"
        $Body = $Body + "<td>$($Change.Domain)</td>"
        $Body = $Body + "<td>$($Change.Added)</td>"
        $Body = $Body + "<td>$($Change.Removed)</td>"
        $Body = $Body + "</tr>"
    }

    $MyServer = ($env:COMPUTERNAME + '.' + $env:USERDNSDOMAIN).ToLower()
    $Body = $Body + "</tbody>"
    $Body = $Body + "</table>"
    $Body = $Body + "<p><em>This script originated from $MyServer</em></p>"


    #Gathering info to send email
    $To = '[email protected]'
    $From = '[email protected]'
    $Subject = 'SPF Change Notification'
    $SmtpServer = 'mailserver.domain.com'

    Send-MailMessage -To $To -From $From -Subject $Subject -BodyAsHtml $Body -SmtpServer $SmtpServer

    $File = Get-ChildItem -Path $ExportPath -File -Filter "*.bak*" | Sort-Object Extension | select FullName, Extension -Last 1
    $Number = $File.Extension -replace '.bak','' -as [int]
    $Number++

    Rename-Item $ExportPath\Audit_RecordSPFBefore.json -NewName Audit_RecordSPFBefore.json.bak$Number
    Rename-Item $ExportPath\Audit_RecordSPFCurrent.json -NewName Audit_RecordSPFBefore.json
}

SPFRecord Powershell

SPF Change Notification Email

Fake records were added and removed to provide a sample output.

Conclusion

Hopefully this script to get SPF record changes using PowerShell would be useful for you to monitor SPF record changes for a domain. As mentioned, I would recommend you setup a job and Automate Powershell Scripts With Task Scheduler to have a better idea of when this was changes.

5/5 - (9 votes)

Paul

Hi, my name is Paul and I am a Sysadmin who enjoys working on various technologies from Microsoft, VMWare, Cisco and many others. Join me as I document my trials and tribulations of the daily grind of System Administration.

Leave a Reply

Your email address will not be published.