public/cis/Test-MtCisDkim.ps1
|
<# .SYNOPSIS Checks state of DKIM for all EXO domains .DESCRIPTION DKIM SHOULD be enabled for all domains. CIS Microsoft 365 Foundations Benchmark v5.0.0 .EXAMPLE Test-MtCisDkim Returns true if DKIM record exists and EXO shows DKIM enabled .LINK https://maester.dev/docs/commands/Test-MtCisDkim #> function Test-MtCisDkim { [CmdletBinding()] [OutputType([bool])] param( # Selector-name for the DKIM record to test.. [string]$Selector = 'selector1' ) if (!(Test-MtConnection ExchangeOnline)) { Add-MtTestResultDetail -SkippedBecause NotConnectedExchange return $null } try { $dkimSigningConfigs = Get-MtExo -Request DkimSigningConfig $acceptedDomains = Get-MtExo -Request AcceptedDomain <# DKIM record without key for parked domains $sendingDomains = $acceptedDomains | Where-Object { -not $_.SendingFromDomainDisabled } #> $dkimRecords = @() foreach ($domain in $acceptedDomains) { $dkimSigningConfig = $dkimSigningConfigs | Where-Object { $_.domain -eq $domain.domainname } if ((Get-Date) -gt $dkimSigningConfig.RotateOnDate) { if ($Selector -ne $dkimSigningConfig.SelectorAfterRotateOnDate) { Write-Verbose "Using DKIM $($dkimSigningConfig.SelectorAfterRotateOnDate) based on EXO config" } $Selector = $dkimSigningConfig.SelectorAfterRotateOnDate } else { if ($Selector -ne $dkimSigningConfig.SelectorBeforeRotateOnDate) { Write-Verbose "Using DKIM $($dkimSigningConfig.SelectorBeforeRotateOnDate) based on EXO config" } $selector = $dkimSigningConfig.SelectorBeforeRotateOnDate } $isMicrosoftDomain = $domain.DomainName.EndsWith(".onmicrosoft.com") $dkimDnsName = if ($isMicrosoftDomain) { $dkimSigningConfig."$($selector)CNAME" } else { "$($Selector)._domainkey.$($domain.DomainName)" } $dkimRecord = Get-MailAuthenticationRecord -DomainName $domain.DomainName -DkimDnsName $dkimDnsName -Records DKIM $dkimRecord | Add-Member -MemberType NoteProperty -Name 'pass' -Value 'Failed' $dkimRecord | Add-Member -MemberType NoteProperty -Name 'reason' -Value '' if ($domain.SendingFromDomainDisabled) { $dkimRecord.pass = 'Skipped' $dkimRecord.reason = 'Parked domain' } elseif (-not $dkimSigningConfig.enabled) { $dkimRecord.pass = 'Failed' $dkimRecord.reason = 'DKIM is disabled' } elseif ($dkimRecord.dkimRecord.GetType().Name -eq 'DKIMRecord') { if (-not $dkimRecord.dkimRecord.validBase64) { $dkimRecord.reason = 'Malformed public key' } else { $dkimRecord.pass = 'Passed' } } elseif ($domain.DomainName -like '*.onmicrosoft.com') { $dkimRecord.reason = "Recommendation: Disable sending from domain" } elseif ($dkimRecord.dkimRecord -like '*not available') { $dkimRecord.pass = 'Skipped' $dkimRecord.reason = $dkimRecord.dkimRecord } else { $dkimRecord.reason = $dkimRecord.dkimRecord } $dkimRecords += $dkimRecord } } catch { Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ return $null } if ('Failed' -in $dkimRecords.pass) { $testResult = $false } elseif ('Failed' -notin $dkimRecords.pass -and 'Passed' -notin $dkimRecords.pass) { Add-MtTestResultDetail -SkippedBecause NotSupported return $null } else { $testResult = $true } try { $portalLink = 'https://security.microsoft.com/authentication?viewid=DKIM' if ($testResult) { $testResultMarkdown = "Well done. Your tenant's domains have DKIM configured and valid records exist.`n`n%TestResult%" } else { $testResultMarkdown = "Your tenant's domains do not have DKIM fully deployed. Review [EXO configuration]($portalLink) and DNS records.`n`n%TestResult%" } $passResult = '✅ Pass' $failResult = '❌ Fail' $skipResult = '🗄️ Skip' $result = "| Domain | Result | Reason |`n" $result += "| --- | --- | --- |`n" foreach ($item in $dkimRecords | Sort-Object -Property domain) { switch ($item.pass) { 'Passed' { $itemResult = $passResult } 'Skipped' { $itemResult = $skipResult } 'Failed' { $itemResult = $failResult } } $result += "| $($item.domain) | $($itemResult) | $($item.reason) |`n" } $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $result Add-MtTestResultDetail -Result $testResultMarkdown return $testResult } catch { Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ return $null } } |