SHELL/2.4.1.ps1
|
$CheckId = "2.4.1" $Title = "Ensure Priority account protection is enabled and configured" $Level = "L1" $BenchmarkType = "Automated" $AuditCommands = [pscustomobject]@{ TenantSettings = "Get-EmailTenantSettings" UserTags = "Get-UserTag (or Get-UserTags)" AlertPolicies = "Get-ProtectionAlert (fallback: Get-AlertPolicy or Get-ActivityAlert)" } function Get-AvailableCommandName { param( [string[]]$Names ) foreach ($Name in $Names) { if (Get-Command -Name $Name -ErrorAction SilentlyContinue) { return $Name } } return $null } function Get-FirstPropertyValue { param( [Parameter(Mandatory = $true)] [object]$InputObject, [Parameter(Mandatory = $true)] [string[]]$PropertyNames ) if ($null -eq $InputObject -or $null -eq $InputObject.PSObject) { return $null } foreach ($PropertyName in $PropertyNames) { $Property = $InputObject.PSObject.Properties[$PropertyName] if ($null -ne $Property) { return $Property.Value } } return $null } function Convert-ToAuditText { param( [AllowNull()] [object]$InputObject ) if ($null -eq $InputObject) { return "" } $Json = "" try { $Json = $InputObject | ConvertTo-Json -Depth 12 -Compress } catch { $Json = "" } $Text = "" try { $Text = $InputObject | Out-String } catch { $Text = "" } return "$Json $Text".ToLowerInvariant().Replace("e-mail", "email") } function Test-RequiredAlert { param( [Parameter(Mandatory = $true)] [object[]]$Alerts, [Parameter(Mandatory = $true)] [string]$ActivityText ) foreach ($Alert in @($Alerts)) { $SearchText = Convert-ToAuditText -InputObject $Alert $ActivityOk = $SearchText.Contains($ActivityText.ToLowerInvariant()) if (-not $ActivityOk) { continue } $SeverityValue = [string](Get-FirstPropertyValue -InputObject $Alert -PropertyNames @("Severity", "AlertSeverity")) $CategoryValue = [string](Get-FirstPropertyValue -InputObject $Alert -PropertyNames @("Category", "AlertCategory")) $DirectionValue = [string](Get-FirstPropertyValue -InputObject $Alert -PropertyNames @("MailDirection", "Direction", "MessageDirection")) $RecipientTagValue = Get-FirstPropertyValue -InputObject $Alert -PropertyNames @("RecipientTags", "UserTags", "RecipientTag") $RecipientTagText = "" if ($null -ne $RecipientTagValue) { $RecipientTagText = (@($RecipientTagValue) -join " ").ToLowerInvariant() } $SeverityOk = if (-not [string]::IsNullOrWhiteSpace($SeverityValue)) { $SeverityValue.Trim().ToLowerInvariant() -eq "high" } else { $SearchText -match "severity.{0,30}high" } $CategoryOk = if (-not [string]::IsNullOrWhiteSpace($CategoryValue)) { $CategoryValue.Trim().ToLowerInvariant() -eq "threat management" } else { $SearchText.Contains("threat management") } $DirectionOk = if (-not [string]::IsNullOrWhiteSpace($DirectionValue)) { $DirectionValue.Trim().ToLowerInvariant() -eq "inbound" } else { $SearchText.Contains("inbound") } $RecipientOk = if (-not [string]::IsNullOrWhiteSpace($RecipientTagText)) { $RecipientTagText.Contains("priority account") } else { $SearchText.Contains("priority account") } if ($SeverityOk -and $CategoryOk -and $DirectionOk -and $RecipientOk) { return [pscustomobject]@{ IsMatch = $true AlertIdentity = [string](Get-FirstPropertyValue -InputObject $Alert -PropertyNames @("Identity", "Id", "Name")) } } } return [pscustomobject]@{ IsMatch = $false AlertIdentity = $null } } try { $FailureReasons = [System.Collections.Generic.List[string]]::new() $ManualReasons = [System.Collections.Generic.List[string]]::new() $Step1Evidence = [ordered]@{ Description = "Priority account protection is enabled." Assessable = $false Passed = $null CommandUsed = $null RawValue = $null } $Step2Evidence = [ordered]@{ Description = "PRIORITY ACCOUNT tag exists and has assigned members." Assessable = $false Passed = $null CommandUsed = $null PriorityTagsFound = 0 PriorityTagMembers = @() AdditionalTags = @() } $Step3Evidence = [ordered]@{ Description = "Required high-severity inbound alert policies for priority accounts are present." Assessable = $false Passed = $null CommandUsed = $null AlertCount = 0 RequiredAlerts = [ordered]@{ MalwareDetected = [ordered]@{ Activity = "Detected malware in an email message" Found = $false AlertIdentity = $null } PhishingDetected = [ordered]@{ Activity = "Phishing email detected at time of delivery" Found = $false AlertIdentity = $null } } } # Step 1: Priority account protection ON $TenantSettingsCommand = Get-AvailableCommandName -Names @("Get-EmailTenantSettings") if ($TenantSettingsCommand) { $Step1Evidence.Assessable = $true $Step1Evidence.CommandUsed = $TenantSettingsCommand $TenantSettings = & $TenantSettingsCommand $ProtectionValue = Get-FirstPropertyValue -InputObject $TenantSettings -PropertyNames @( "EnablePriorityAccountProtection", "PriorityAccountProtectionEnabled", "PriorityAccountProtection", "IsPriorityAccountProtectionEnabled" ) $Step1Evidence.RawValue = $ProtectionValue if ($null -eq $ProtectionValue) { $Step1Evidence.Passed = $null $ManualReasons.Add("Unable to determine whether Priority account protection is enabled from tenant settings output.") } else { $Enabled = [bool]$ProtectionValue $Step1Evidence.Passed = $Enabled if (-not $Enabled) { $FailureReasons.Add("Priority account protection is not enabled.") } } } else { $ManualReasons.Add("Get-EmailTenantSettings cmdlet is unavailable in the current session.") } # Step 2: PRIORITY ACCOUNT tag configured $UserTagCommand = Get-AvailableCommandName -Names @("Get-UserTag", "Get-UserTags") if ($UserTagCommand) { $Step2Evidence.Assessable = $true $Step2Evidence.CommandUsed = $UserTagCommand $AllTags = @(& $UserTagCommand) $PriorityTags = @($AllTags | Where-Object { $TagName = [string](Get-FirstPropertyValue -InputObject $_ -PropertyNames @("Name", "DisplayName", "Identity")) $TagName.Trim().ToLowerInvariant() -eq "priority account" }) $Step2Evidence.PriorityTagsFound = @($PriorityTags).Count $Step2Evidence.AdditionalTags = @($AllTags | Where-Object { $_ -notin $PriorityTags } | ForEach-Object { [string](Get-FirstPropertyValue -InputObject $_ -PropertyNames @("Name", "DisplayName", "Identity")) } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) if (@($PriorityTags).Count -eq 0) { $Step2Evidence.Passed = $false $FailureReasons.Add("PRIORITY ACCOUNT user tag was not found.") } else { $MemberEntries = @() foreach ($Tag in $PriorityTags) { $Members = Get-FirstPropertyValue -InputObject $Tag -PropertyNames @( "Members", "Users", "Recipients", "MemberUsers", "UserList" ) $NormalizedMembers = @($Members | ForEach-Object { [string]$_ } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) $MemberEntries += $NormalizedMembers } $Step2Evidence.PriorityTagMembers = @($MemberEntries | Select-Object -Unique) $HasMembers = @($Step2Evidence.PriorityTagMembers).Count -gt 0 $Step2Evidence.Passed = $HasMembers if (-not $HasMembers) { $FailureReasons.Add("PRIORITY ACCOUNT tag exists but has no assigned users or groups.") } } } else { $ManualReasons.Add("No user-tag cmdlet is available (expected Get-UserTag/Get-UserTags).") } # Step 3: Two required priority-account alert policies configured $AlertCommand = Get-AvailableCommandName -Names @("Get-ProtectionAlert", "Get-AlertPolicy", "Get-ActivityAlert") if ($AlertCommand) { $Step3Evidence.Assessable = $true $Step3Evidence.CommandUsed = $AlertCommand $Alerts = @(& $AlertCommand) $Step3Evidence.AlertCount = @($Alerts).Count if (@($Alerts).Count -eq 0) { $Step3Evidence.Passed = $false $FailureReasons.Add("No alert policies were returned for evaluation.") } else { $MalwareCheck = Test-RequiredAlert -Alerts $Alerts -ActivityText "detected malware in an email message" $PhishingCheck = Test-RequiredAlert -Alerts $Alerts -ActivityText "phishing email detected at time of delivery" $Step3Evidence.RequiredAlerts.MalwareDetected.Found = [bool]$MalwareCheck.IsMatch $Step3Evidence.RequiredAlerts.MalwareDetected.AlertIdentity = $MalwareCheck.AlertIdentity $Step3Evidence.RequiredAlerts.PhishingDetected.Found = [bool]$PhishingCheck.IsMatch $Step3Evidence.RequiredAlerts.PhishingDetected.AlertIdentity = $PhishingCheck.AlertIdentity $Step3Evidence.Passed = ([bool]$MalwareCheck.IsMatch -and [bool]$PhishingCheck.IsMatch) if (-not [bool]$MalwareCheck.IsMatch) { $FailureReasons.Add("Missing required priority-account alert for activity: Detected malware in an email message (High, Threat management, Inbound, Recipient Tags include Priority account).") } if (-not [bool]$PhishingCheck.IsMatch) { $FailureReasons.Add("Missing required priority-account alert for activity: Phishing email detected at time of delivery (High, Threat management, Inbound, Recipient Tags include Priority account).") } } } else { $ManualReasons.Add("No alert-policy cmdlet is available (expected Get-ProtectionAlert/Get-AlertPolicy/Get-ActivityAlert).") } $Status = "PASS" $Pass = $true $ErrorMessage = $null if ($FailureReasons.Count -gt 0) { $Status = "FAIL" $Pass = $false $ErrorMessage = ($FailureReasons -join " ") } elseif ($ManualReasons.Count -gt 0) { $Status = "MANUAL_REVIEW" $Pass = $null $ErrorMessage = "Manual review required: $($ManualReasons -join " ")" } [pscustomobject]@{ CheckId = $CheckId Title = $Title Level = $Level BenchmarkType = $BenchmarkType Status = $Status Pass = $Pass Evidence = [pscustomobject]@{ AuditCommands = $AuditCommands AuditUiReference = @( "Step 1: E-mail & collaboration > Priority account protection = On", "Step 2: PRIORITY ACCOUNT tag exists and members are defined", "Step 3: Alert policies include malware/phishing activities with High severity, Threat management category, Inbound direction, and Priority account recipient tag" ) Steps = [pscustomobject]@{ Step1 = [pscustomobject]$Step1Evidence Step2 = [pscustomobject]$Step2Evidence Step3 = [pscustomobject]$Step3Evidence } ManualReviewReasons = @($ManualReasons) SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1" } Error = $ErrorMessage Timestamp = Get-Date } } catch { [pscustomobject]@{ CheckId = $CheckId Title = $Title Level = $Level BenchmarkType = $BenchmarkType Status = "ERROR" Pass = $null Evidence = [pscustomobject]@{ AuditCommands = $AuditCommands SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1" } Error = $_.Exception.Message Timestamp = Get-Date } } |