Skip to content

Commit f37d68a

Browse files
committed
Fixes ORCA235
1 parent 28ba94b commit f37d68a

1 file changed

Lines changed: 38 additions & 16 deletions

File tree

Modules/CIPPTests/Public/Tests/ORCA/Identity/Invoke-CippTestORCA235.ps1

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,53 @@ function Invoke-CippTestORCA235 {
66
param($Tenant)
77

88
try {
9-
$AcceptedDomains = Get-CIPPTestData -TenantFilter $Tenant -Type 'ExoAcceptedDomains'
9+
$Results = Get-CIPPDomainAnalyser -TenantFilter $Tenant
1010

11-
if (-not $AcceptedDomains) {
12-
Add-CippTestResult -TenantFilter $Tenant -TestId 'ORCA235' -TestType 'Identity' -Status 'Skipped' -ResultMarkdown 'No accepted domains found in database.' -Risk 'High' -Name 'SPF records setup for custom domains' -UserImpact 'High' -ImplementationEffort 'Medium' -Category 'Configuration'
11+
if (-not $Results) {
12+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ORCA235' -TestType 'Identity' -Status 'Skipped' -ResultMarkdown 'No Domain Analyser results found for this tenant. Run the CIPP Domain Analyser to populate domain health data.' -Risk 'High' -Name 'SPF records setup for custom domains' -UserImpact 'High' -ImplementationEffort 'Medium' -Category 'Configuration'
1313
return
1414
}
1515

16-
# Note: This test would ideally check DNS SPF records
17-
# Since we don't have DNS query capability here, we'll provide informational guidance
16+
# ORCA scopes this to custom domains; onmicrosoft.com is handled by Microsoft.
17+
$CustomDomains = $Results | Where-Object { $_.Domain -notlike '*.onmicrosoft.com' }
1818

19-
$CustomDomains = $AcceptedDomains | Where-Object { $_.DomainName -notlike '*.onmicrosoft.com' }
19+
if (-not $CustomDomains -or $CustomDomains.Count -eq 0) {
20+
$Status = 'Passed'
21+
$Result = [System.Text.StringBuilder]::new('No custom domains found. Only onmicrosoft.com in use.')
22+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ORCA235' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'High' -Name 'SPF records setup for custom domains' -UserImpact 'High' -ImplementationEffort 'Medium' -Category 'Configuration'
23+
return
24+
}
25+
26+
$FailedDomains = [System.Collections.Generic.List[object]]::new()
27+
$PassedDomains = [System.Collections.Generic.List[object]]::new()
28+
29+
foreach ($Domain in $CustomDomains) {
30+
# Valid SPF must start with v=spf1 AND end with -all (hard fail).
31+
# ~all (soft fail), ?all (neutral), and +all (pass all) are insufficient.
32+
# Third-party includes/IPs (Mimecast/Proofpoint/marketing) are fine alongside -all.
33+
$Spf = [string]$Domain.ActualSPFRecord
34+
$HasSpf = $Spf -match 'v=spf1'
35+
$HasHardFail = $Spf -match '-all\s*$'
36+
37+
if ($HasSpf -and $HasHardFail) {
38+
$PassedDomains.Add($Domain) | Out-Null
39+
} else {
40+
$FailedDomains.Add($Domain) | Out-Null
41+
}
42+
}
2043

21-
if ($CustomDomains.Count -eq 0) {
44+
if ($FailedDomains.Count -eq 0) {
2245
$Status = 'Passed'
23-
$Result = [System.Text.StringBuilder]::new("No custom domains found. Only using onmicrosoft.com domain.`n`n")
24-
$null = $Result.Append("**Total Domains:** $($AcceptedDomains.Count)")
46+
$Result = [System.Text.StringBuilder]::new("All $($PassedDomains.Count) custom domains have a valid SPF record ending in -all.")
2547
} else {
26-
$Status = 'Informational'
27-
$Result = [System.Text.StringBuilder]::new("Found $($CustomDomains.Count) custom domains that should have SPF records configured.`n`n")
28-
$null = $Result.Append("**Custom Domains:**`n`n")
29-
foreach ($Domain in $CustomDomains) {
30-
$null = $Result.Append("- $($Domain.DomainName)`n")
48+
$Status = 'Failed'
49+
$Result = [System.Text.StringBuilder]::new("$($FailedDomains.Count) of $($CustomDomains.Count) custom domains are missing a valid SPF record or do not end in -all (hard fail).`n`n")
50+
$null = $Result.Append("| Domain | SPF Record |`n| :----- | :--------- |`n")
51+
foreach ($Domain in ($FailedDomains | Select-Object -First 25)) {
52+
$Display = if ([string]::IsNullOrWhiteSpace($Domain.ActualSPFRecord)) { '*(none)*' } else { $Domain.ActualSPFRecord }
53+
$null = $Result.Append("| $($Domain.Domain) | $Display |`n")
3154
}
32-
$null = $Result.Append("`n**Action Required:** Verify that each custom domain has an SPF record including Microsoft 365:`n")
33-
$null = $Result.Append("``v=spf1 include:spf.protection.outlook.com -all``")
55+
$null = $Result.Append("`n**Remediation:** Publish an SPF TXT record ending in `-all` (hard fail). For Microsoft 365 only: `v=spf1 include:spf.protection.outlook.com -all`. If routing through a third-party gateway, include that provider alongside (e.g. Mimecast, Proofpoint, marketing services), but keep `-all` at the end. Avoid `~all`, `?all`, and especially `+all`.")
3456
}
3557

3658
Add-CippTestResult -TenantFilter $Tenant -TestId 'ORCA235' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'High' -Name 'SPF records setup for custom domains' -UserImpact 'High' -ImplementationEffort 'Medium' -Category 'Configuration'

0 commit comments

Comments
 (0)