diff --git a/helpers/Build-Help.ps1 b/helpers/Build-Help.ps1 index a5da881..bebbbf8 100644 --- a/helpers/Build-Help.ps1 +++ b/helpers/Build-Help.ps1 @@ -4,7 +4,7 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1 <# - $ver = "v0.1.8" + $ver = "v0.1.9" git checkout main git pull origin main git tag -a $ver -m "Release version $ver refactor Update" diff --git a/source/tests/Test-BlockSharedMailboxSignIn.ps1 b/source/tests/Test-BlockSharedMailboxSignIn.ps1 index d1af582..db217e1 100644 --- a/source/tests/Test-BlockSharedMailboxSignIn.ps1 +++ b/source/tests/Test-BlockSharedMailboxSignIn.ps1 @@ -2,29 +2,44 @@ function Test-BlockSharedMailboxSignIn { [CmdletBinding()] [OutputType([CISAuditResult])] param ( - # Aligned # Parameters can be added if needed ) begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $recnum = "1.2.2" + + # Conditions for 1.2.2 (L1) Ensure sign-in to shared mailboxes is blocked + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: No shared mailboxes have the "Sign-in blocked" option disabled in the properties pane on the Microsoft 365 admin center. + # - Condition B: Using PowerShell, the `AccountEnabled` property for all shared mailboxes is set to `False`. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: One or more shared mailboxes have the "Sign-in blocked" option enabled in the properties pane on the Microsoft 365 admin center. + # - Condition B: Using PowerShell, the `AccountEnabled` property for one or more shared mailboxes is set to `True`. } process { - try { - # 1.2.2 (L1) Ensure sign-in to shared mailboxes is blocked - - # Retrieve shared mailbox details + # Step: Retrieve shared mailbox details $MBX = Get-EXOMailbox -RecipientTypeDetails SharedMailbox + + # Step: Retrieve details of shared mailboxes from Azure AD (Condition B: Pass/Fail) $sharedMailboxDetails = $MBX | ForEach-Object { Get-AzureADUser -ObjectId $_.ExternalDirectoryObjectId } + + # Step: Identify enabled mailboxes (Condition B: Pass/Fail) $enabledMailboxes = $sharedMailboxDetails | Where-Object { $_.AccountEnabled } | ForEach-Object { $_.DisplayName } $allBlocked = $enabledMailboxes.Count -eq 0 - # Prepare failure reasons and details based on compliance + # Step: Determine failure reasons based on enabled mailboxes (Condition A & B: Fail) $failureReasons = if (-not $allBlocked) { "Some mailboxes have sign-in enabled: $($enabledMailboxes -join ', ')" } @@ -32,6 +47,7 @@ function Test-BlockSharedMailboxSignIn { "N/A" } + # Step: Prepare details for the audit result (Condition A & B: Pass/Fail) $details = if ($allBlocked) { "All shared mailboxes have sign-in blocked." } @@ -39,10 +55,10 @@ function Test-BlockSharedMailboxSignIn { "Enabled Mailboxes: $($enabledMailboxes -join ', ')" } - # Create and populate the CISAuditResult object + # Step: Create and populate the CISAuditResult object $params = @{ Rec = $recnum - Result = $allBlocked + Result = $allBlocked # Pass: Condition A, Condition B Status = if ($allBlocked) { "Pass" } else { "Fail" } Details = $details FailureReason = $failureReasons diff --git a/source/tests/Test-CommonAttachmentFilter.ps1 b/source/tests/Test-CommonAttachmentFilter.ps1 index 3341ca5..0384880 100644 --- a/source/tests/Test-CommonAttachmentFilter.ps1 +++ b/source/tests/Test-CommonAttachmentFilter.ps1 @@ -7,6 +7,24 @@ function Test-CommonAttachmentFilter { ) begin { + <# + Conditions for 2.1.2 (L1) Ensure the Common Attachment Types Filter is enabled + + Validate test for a pass: + - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + - Specific conditions to check: + - Condition A: The Common Attachment Types Filter is enabled in the Microsoft 365 Security & Compliance Center. + - Condition B: Using Exchange Online PowerShell, verify that the `EnableFileFilter` property of the default malware filter policy is set to `True`. + - Condition C: Ensure that the setting is enabled in the highest priority policy listed if custom policies exist. + + Validate test for a fail: + - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + - Specific conditions to check: + - Condition A: The Common Attachment Types Filter is not enabled in the Microsoft 365 Security & Compliance Center. + - Condition B: Using Exchange Online PowerShell, verify that the `EnableFileFilter` property of the default malware filter policy is set to `False`. + - Condition C: Ensure that the setting is not enabled in the highest priority policy listed if custom policies exist. + #> + # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed @@ -16,6 +34,8 @@ function Test-CommonAttachmentFilter { process { try { # 2.1.2 (L1) Ensure the Common Attachment Types Filter is enabled + # Condition A: The Common Attachment Types Filter is enabled in the Microsoft 365 Security & Compliance Center. + # Condition B: Using Exchange Online PowerShell, verify that the `EnableFileFilter` property of the default malware filter policy is set to `True`. # Retrieve the attachment filter policy $attachmentFilter = Get-MalwareFilterPolicy -Identity Default | Select-Object EnableFileFilter @@ -23,6 +43,8 @@ function Test-CommonAttachmentFilter { # Prepare failure reasons and details based on compliance $failureReasons = if (-not $result) { + # Condition A: The Common Attachment Types Filter is not enabled in the Microsoft 365 Security & Compliance Center. + # Condition B: Using Exchange Online PowerShell, verify that the `EnableFileFilter` property of the default malware filter policy is set to `False`. "Common Attachment Types Filter is disabled" } else { diff --git a/source/tests/Test-CustomerLockbox.ps1 b/source/tests/Test-CustomerLockbox.ps1 index 8396ffc..cc67246 100644 --- a/source/tests/Test-CustomerLockbox.ps1 +++ b/source/tests/Test-CustomerLockbox.ps1 @@ -9,43 +9,58 @@ function Test-CustomerLockbox { begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $recnum = "1.3.6" + + # Conditions for 1.3.6 (L2) Ensure the customer lockbox feature is enabled (Automated) + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: In the Microsoft 365 admin center, the box labeled "Customer Lockbox Requests" is checked. + # - Condition B: Using the SecureScore portal, the Customer Lockbox feature is enabled. + # - Condition C: Using PowerShell, the Customer Lockbox feature is set to `True`. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: In the Microsoft 365 admin center, the box labeled "Customer Lockbox Requests" is not checked. + # - Condition B: Using the SecureScore portal, the Customer Lockbox feature is not enabled. + # - Condition C: Using PowerShell, the Customer Lockbox feature is not set to `True`. } process { - try { - # 1.3.6 (L2) Ensure the customer lockbox feature is enabled + # Step: Retrieve the organization configuration (Condition C: Pass/Fail) + $orgConfig = Get-OrganizationConfig | Select-Object CustomerLockBoxEnabled + $customerLockboxEnabled = $orgConfig.CustomerLockBoxEnabled - # Retrieve the organization configuration - $orgConfig = Get-OrganizationConfig | Select-Object CustomerLockBoxEnabled - $customerLockboxEnabled = $orgConfig.CustomerLockBoxEnabled + # Step: Prepare failure reasons and details based on compliance (Condition A, B, & C: Fail) + $failureReasons = if (-not $customerLockboxEnabled) { + "Customer lockbox feature is not enabled." + } + else { + "N/A" + } - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $customerLockboxEnabled) { - "Customer lockbox feature is not enabled." - } - else { - "N/A" - } + # Step: Prepare details for the audit result (Condition A, B, & C: Pass/Fail) + $details = if ($customerLockboxEnabled) { + "Customer Lockbox Enabled: True" + } + else { + "Customer Lockbox Enabled: False" + } - $details = if ($customerLockboxEnabled) { - "Customer Lockbox Enabled: True" - } - else { - "Customer Lockbox Enabled: False" - } - - # Create and populate the CISAuditResult object # - $params = @{ - Rec = $recnum - Result = $customerLockboxEnabled - Status = if ($customerLockboxEnabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params + # Step: Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $customerLockboxEnabled + Status = if ($customerLockboxEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } catch { Write-Error "An error occurred during the test: $_" diff --git a/source/tests/Test-ExternalSharingCalendars.ps1 b/source/tests/Test-ExternalSharingCalendars.ps1 index ed5e941..2b1946e 100644 --- a/source/tests/Test-ExternalSharingCalendars.ps1 +++ b/source/tests/Test-ExternalSharingCalendars.ps1 @@ -12,17 +12,28 @@ function Test-ExternalSharingCalendars { # Initialization code, if needed $recnum = "1.3.3" + + # Conditions for 1.3.3 (L2) Ensure 'External sharing' of calendars is not available (Automated) + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: In the Microsoft 365 admin center, external calendar sharing is disabled. + # - Condition B: Using the Exchange Online PowerShell Module, the `OrganizationConfig` property `ExternalSharingEnabled` is set to `False`. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: In the Microsoft 365 admin center, external calendar sharing is enabled. + # - Condition B: Using the Exchange Online PowerShell Module, the `OrganizationConfig` property `ExternalSharingEnabled` is set to `True`. } process { - try { - # 1.3.3 (L2) Ensure 'External sharing' of calendars is not available (Automated) - - # Retrieve sharing policies related to calendar sharing + # Step: Retrieve sharing policies related to calendar sharing $sharingPolicies = Get-SharingPolicy | Where-Object { $_.Domains -like '*CalendarSharing*' } - # Check if calendar sharing is disabled in all applicable policies + # Step (Condition A & B: Pass/Fail): Check if calendar sharing is disabled in all applicable policies $isExternalSharingDisabled = $true $sharingPolicyDetails = @() foreach ($policy in $sharingPolicies) { @@ -32,7 +43,7 @@ function Test-ExternalSharingCalendars { } } - # Prepare failure reasons and details based on compliance + # Step: Prepare failure reasons and details based on compliance (Condition A & B: Fail) $failureReasons = if (-not $isExternalSharingDisabled) { "Calendar sharing with external users is enabled in one or more policies." } @@ -40,6 +51,7 @@ function Test-ExternalSharingCalendars { "N/A" } + # Step: Prepare details for the audit result (Condition A & B: Pass/Fail) $details = if ($isExternalSharingDisabled) { "Calendar sharing with external users is disabled." } @@ -47,7 +59,7 @@ function Test-ExternalSharingCalendars { "Enabled Sharing Policies: $($sharingPolicyDetails -join ', ')" } - # Create and populate the CISAuditResult object + # Step: Create and populate the CISAuditResult object $params = @{ Rec = $recnum Result = $isExternalSharingDisabled diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index 0c71f28..865d02e 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -2,13 +2,27 @@ function Test-GlobalAdminsCount { [CmdletBinding()] [OutputType([CISAuditResult])] param ( - # Aligned # Define your parameters here if needed ) begin { - # Dot source the class script if necessary + # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 + # Conditions for 1.1.3 (L1) Ensure that between two and four global admins are designated + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: The number of global admins is at least 2. + # - Condition B: The number of global admins is at most 4. + # - Condition C: The list of global admin usernames is accurately retrieved and displayed. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: The number of global admins is less than 2. + # - Condition B: The number of global admins is more than 4. + # - Condition C: Any discrepancies or errors in retrieving the list of global admin usernames. # Initialization code, if needed $recnum = "1.1.3" @@ -16,17 +30,21 @@ function Test-GlobalAdminsCount { process { try { - # 1.1.3 (L1) Ensure that between two and four global admins are designated - - # Retrieve global admin role and members + # Step: Retrieve global admin role $globalAdminRole = Get-MgDirectoryRole -Filter "RoleTemplateId eq '62e90394-69f5-4237-9190-012177145e10'" + + # Step: Retrieve global admin members $globalAdmins = Get-MgDirectoryRoleMember -DirectoryRoleId $globalAdminRole.Id + + # Step: Count the number of global admins $globalAdminCount = $globalAdmins.Count + + # Step: Retrieve and format the usernames of global admins $globalAdminUsernames = ($globalAdmins | ForEach-Object { "$($_.AdditionalProperties["displayName"]) ($($_.AdditionalProperties["userPrincipalName"]))" }) -join ', ' - # Prepare failure reasons and details based on compliance + # Step: Determine failure reasons based on global admin count $failureReasons = if ($globalAdminCount -lt 2) { "Less than 2 global admins: $globalAdminUsernames" } @@ -37,9 +55,10 @@ function Test-GlobalAdminsCount { "N/A" } + # Step: Prepare details for the audit result $details = "Count: $globalAdminCount; Users: $globalAdminUsernames" - # Create and populate the CISAuditResult object + # Step: Create and populate the CISAuditResult object $params = @{ Rec = $recnum Result = $globalAdminCount -ge 2 -and $globalAdminCount -le 4 diff --git a/source/tests/Test-ManagedApprovedPublicGroups.ps1 b/source/tests/Test-ManagedApprovedPublicGroups.ps1 index 073d540..829f202 100644 --- a/source/tests/Test-ManagedApprovedPublicGroups.ps1 +++ b/source/tests/Test-ManagedApprovedPublicGroups.ps1 @@ -2,25 +2,37 @@ function Test-ManagedApprovedPublicGroups { [CmdletBinding()] [OutputType([CISAuditResult])] param ( - # Aligned # Parameters can be added if needed ) begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $recnum = "1.2.1" + + # Conditions for 1.2.1 (L2) Ensure that only organizationally managed/approved public groups exist (Automated) + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: No groups have the status 'Public' in the privacy column on the Active teams and groups page. + # - Condition B: Using Microsoft Graph PowerShell, all groups return a status other than 'Public' when checked. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: One or more groups have the status 'Public' in the privacy column on the Active teams and groups page. + # - Condition B: Using Microsoft Graph PowerShell, one or more groups return a status of 'Public' when checked. } process { try { - # 1.2.1 (L2) Ensure that only organizationally managed/approved public groups exist (Automated) - - # Retrieve all public groups + # Step: Retrieve all groups with visibility set to 'Public' $allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq "Public" } | Select-Object DisplayName, Visibility - # Prepare failure reasons and details based on compliance + # Step: Determine failure reasons based on the presence of public groups $failureReasons = if ($null -ne $allGroups -and $allGroups.Count -gt 0) { "There are public groups present that are not organizationally managed/approved." } @@ -28,6 +40,7 @@ function Test-ManagedApprovedPublicGroups { "N/A" } + # Step: Prepare details for the audit result $details = if ($null -eq $allGroups -or $allGroups.Count -eq 0) { "No public groups found." } @@ -36,7 +49,7 @@ function Test-ManagedApprovedPublicGroups { "Public groups found: $($groupDetails -join ', ')" } - # Create and populate the CISAuditResult object + # Step: Create and populate the CISAuditResult object $params = @{ Rec = $recnum Result = $null -eq $allGroups -or $allGroups.Count -eq 0 @@ -61,7 +74,7 @@ function Test-ManagedApprovedPublicGroups { } end { - # Return auditResults + # Return the audit result return $auditResult } } diff --git a/source/tests/Test-NotifyMalwareInternal.ps1 b/source/tests/Test-NotifyMalwareInternal.ps1 index 1e466fb..6c15c9a 100644 --- a/source/tests/Test-NotifyMalwareInternal.ps1 +++ b/source/tests/Test-NotifyMalwareInternal.ps1 @@ -7,6 +7,22 @@ function Test-NotifyMalwareInternal { ) begin { + <# + # Conditions for 2.1.3 (L1) Ensure notifications for internal users sending malware is Enabled + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: Notifications for internal users sending malware are enabled in the Microsoft 365 Security & Compliance Center. + # - Condition B: Using PowerShell, the `NotifyInternal` property in the anti-malware policy is set to `True` and includes at least one valid email address for notifications. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: Notifications for internal users sending malware are not enabled in the Microsoft 365 Security & Compliance Center. + # - Condition B: Using PowerShell, the `NotifyInternal` property in the anti-malware policy is set to `False` or does not include any valid email addresses for notifications. + #> + # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed @@ -19,8 +35,9 @@ function Test-NotifyMalwareInternal { # Retrieve all 'Custom' malware filter policies and check notification settings $malwareNotifications = Get-MalwareFilterPolicy | Where-Object { $_.RecommendedPolicyType -eq 'Custom' } - $policiesToReport = @() + # Condition B: Using PowerShell, the `NotifyInternal` property in the anti-malware policy is set to `True` and includes at least one valid email address for notifications. + $policiesToReport = @() foreach ($policy in $malwareNotifications) { if ($policy.EnableInternalSenderAdminNotifications -ne $true) { $policiesToReport += "$($policy.Identity): Notifications Disabled" @@ -35,6 +52,7 @@ function Test-NotifyMalwareInternal { "N/A" } else { + # Condition A: Notifications for internal users sending malware are not enabled in the Microsoft 365 Security & Compliance Center. "Some custom policies do not have notifications for internal users sending malware enabled." } diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index b94a22e..5d0723e 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -7,6 +7,7 @@ function Test-PasswordNeverExpirePolicy { ) begin { + # .TODO add supported services to output details. ({Email, OfficeCommunicationsOnline, Intune}) # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed @@ -17,11 +18,25 @@ function Test-PasswordNeverExpirePolicy { # Add headers for the details $detailsList += "Domain|Validity Period|IsDefault" + + # Conditions for 1.3.1 (L1) Ensure the 'Password expiration policy' is set to 'Set passwords to never expire (recommended)' + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: Password expiration policy is set to "Set passwords to never expire" in the Microsoft 365 admin center. + # - Condition B: Using Microsoft Graph PowerShell, the `PasswordPolicies` property for all users is set to `DisablePasswordExpiration`. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: Password expiration policy is not set to "Set passwords to never expire" in the Microsoft 365 admin center. + # - Condition B: Using Microsoft Graph PowerShell, the `PasswordPolicies` property for one or more users is not set to `DisablePasswordExpiration`. } process { try { - # Retrieve all domains or a specific domain + # Step: Retrieve all domains or a specific domain $domains = if ($DomainName) { Get-MgDomain -DomainId $DomainName } else { @@ -31,14 +46,14 @@ function Test-PasswordNeverExpirePolicy { foreach ($domain in $domains) { $domainName = $domain.Id $isDefault = $domain.IsDefault - # Retrieve password expiration policy + # Step (Condition A): Retrieve password expiration policy $passwordPolicy = $domain.PasswordValidityPeriodInDays - # Determine if the policy is compliant + # Step (Condition A & B): Determine if the policy is compliant $isCompliant = $passwordPolicy -eq 0 $overallResult = $overallResult -and $isCompliant - # Prepare failure reasons and details based on compliance + # Step (Condition A & B): Prepare failure reasons and details based on compliance $failureReasons = if ($isCompliant) { "N/A" } else { @@ -56,7 +71,7 @@ function Test-PasswordNeverExpirePolicy { $finalFailureReason = $failureReasonsList -join "`n" $finalDetails = $detailsList -join "`n" - # Create and populate the CISAuditResult object + # Step: Create and populate the CISAuditResult object $params = @{ Rec = $recnum Result = $overallResult diff --git a/source/tests/Test-SafeAttachmentsPolicy.ps1 b/source/tests/Test-SafeAttachmentsPolicy.ps1 index 18a90a2..8b5fe06 100644 --- a/source/tests/Test-SafeAttachmentsPolicy.ps1 +++ b/source/tests/Test-SafeAttachmentsPolicy.ps1 @@ -9,8 +9,29 @@ function Test-SafeAttachmentsPolicy { begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $recnum = "2.1.4" + + <# + Conditions for 2.1.4 (L2) Ensure Safe Attachments policy is enabled + + Validate test for a pass: + - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + - Specific conditions to check: + - Condition A: The Safe Attachments policy is enabled in the Microsoft 365 Defender portal. + - Condition B: The policy covers all recipients within the organization. + - Condition C: The policy action is set to "Dynamic Delivery" or "Quarantine". + - Condition D: The policy is not disabled. + + Validate test for a fail: + - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + - Specific conditions to check: + - Condition A: The Safe Attachments policy is not enabled in the Microsoft 365 Defender portal. + - Condition B: The policy does not cover all recipients within the organization. + - Condition C: The policy action is not set to "Dynamic Delivery" or "Quarantine". + - Condition D: The policy is disabled. + #> } process { @@ -20,8 +41,12 @@ function Test-SafeAttachmentsPolicy { # Retrieve all Safe Attachment policies where Enable is set to True $safeAttachmentPolicies = Get-SafeAttachmentPolicy | Where-Object { $_.Enable -eq $true } - # Determine result and details based on the presence of enabled policies + # Condition A: Check if any Safe Attachments policy is enabled $result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0 + + # Condition B, C, D: Additional checks can be added here if more detailed policy attributes are required + + # Determine details and failure reasons based on the presence of enabled policies $details = if ($result) { "Enabled Safe Attachments Policies: $($safeAttachmentPolicies.Name -join ', ')" } @@ -66,4 +91,3 @@ function Test-SafeAttachmentsPolicy { } } -# Additional helper functions (if any) diff --git a/source/tests/Test-SafeAttachmentsTeams.ps1 b/source/tests/Test-SafeAttachmentsTeams.ps1 index 1fae789..8c0b5f3 100644 --- a/source/tests/Test-SafeAttachmentsTeams.ps1 +++ b/source/tests/Test-SafeAttachmentsTeams.ps1 @@ -9,6 +9,23 @@ function Test-SafeAttachmentsTeams { begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 + + # Conditions for 2.1.5 (L2) Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled + # + # Validate test for a pass: + # - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + # - Specific conditions to check: + # - Condition A: Safe Attachments for SharePoint is enabled. + # - Condition B: Safe Attachments for OneDrive is enabled. + # - Condition C: Safe Attachments for Microsoft Teams is enabled. + # + # Validate test for a fail: + # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + # - Specific conditions to check: + # - Condition A: Safe Attachments for SharePoint is not enabled. + # - Condition B: Safe Attachments for OneDrive is not enabled. + # - Condition C: Safe Attachments for Microsoft Teams is not enabled. + # Initialization code, if needed $recnum = "2.1.5" } @@ -27,6 +44,10 @@ function Test-SafeAttachmentsTeams { $_.AllowSafeDocsOpen -eq $false } + # Condition A: Check Safe Attachments for SharePoint + # Condition B: Check Safe Attachments for OneDrive + # Condition C: Check Safe Attachments for Microsoft Teams + # Determine the result based on the ATP policy settings $result = $null -ne $atpPolicyResult $details = if ($result) { @@ -71,6 +92,4 @@ function Test-SafeAttachmentsTeams { # Return the audit result return $auditResult } -} - -# Additional helper functions (if any) +} \ No newline at end of file diff --git a/source/tests/Test-SafeLinksOfficeApps.ps1 b/source/tests/Test-SafeLinksOfficeApps.ps1 index aa30dbc..37a864b 100644 --- a/source/tests/Test-SafeLinksOfficeApps.ps1 +++ b/source/tests/Test-SafeLinksOfficeApps.ps1 @@ -11,6 +11,32 @@ function Test-SafeLinksOfficeApps { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed $recnum = "2.1.1" + + <# + Conditions for 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled + + Validate test for a pass: + - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + - Specific conditions to check: + - Condition A: In the Microsoft 365 security center, Safe Links policy for Office applications is enabled and the following protection settings are set: + - Office 365 Apps: On + - Teams: On + - Email: On + - Click protection settings: On + - Do not track when users click safe links: Off + - Condition B: Using the Exchange Online PowerShell Module, Safe Links policies are retrieved, and the relevant policy shows Safe Links for Office applications is enabled. + + Validate test for a fail: + - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + - Specific conditions to check: + - Condition A: In the Microsoft 365 security center, Safe Links policy for Office applications is not enabled or one or more of the required protection settings are not set correctly. + - Office 365 Apps: Off + - Teams: Off + - Email: Off + - Click protection settings: Off + - Do not track when users click safe links: On + - Condition B: Using the Exchange Online PowerShell Module, Safe Links policies are retrieved, and the relevant policy shows Safe Links for Office applications is not enabled. + #> } process { @@ -28,16 +54,13 @@ function Test-SafeLinksOfficeApps { $policyDetails = Get-SafeLinksPolicy -Identity $policy.Name # Check each required property and record failures + # Condition A: Checking policy settings $failures = @() - if ($policyDetails.EnableSafeLinksForEmail -ne $true) { $failures += "EnableSafeLinksForEmail: False" } - if ($policyDetails.EnableSafeLinksForTeams -ne $true) { $failures += "EnableSafeLinksForTeams: False" } - if ($policyDetails.EnableSafeLinksForOffice -ne $true) { $failures += "EnableSafeLinksForOffice: False" } - if ($policyDetails.TrackClicks -ne $true) { $failures += "TrackClicks: False" } - if ($policyDetails.AllowClickThrough -ne $false) { $failures += "AllowClickThrough: True" } - if ($policyDetails.ScanUrls -ne $true) { $failures += "ScanUrls: False" } - if ($policyDetails.EnableForInternalSenders -ne $true) { $failures += "EnableForInternalSenders: False" } - if ($policyDetails.DeliverMessageAfterScan -ne $true) { $failures += "DeliverMessageAfterScan: False" } - if ($policyDetails.DisableUrlRewrite -ne $false) { $failures += "DisableUrlRewrite: True" } + if ($policyDetails.EnableSafeLinksForEmail -ne $true) { $failures += "EnableSafeLinksForEmail: False" } # Email: On + if ($policyDetails.EnableSafeLinksForTeams -ne $true) { $failures += "EnableSafeLinksForTeams: False" } # Teams: On + if ($policyDetails.EnableSafeLinksForOffice -ne $true) { $failures += "EnableSafeLinksForOffice: False" } # Office 365 Apps: On + if ($policyDetails.TrackClicks -ne $true) { $failures += "TrackClicks: False" } # Click protection settings: On + if ($policyDetails.AllowClickThrough -ne $false) { $failures += "AllowClickThrough: True" } # Do not track when users click safe links: Off # Only add details for policies that have misconfigurations if ($failures.Count -gt 0) { @@ -46,6 +69,7 @@ function Test-SafeLinksOfficeApps { } # Prepare the final result + # Condition B: Ensuring no misconfigurations $result = $misconfiguredDetails.Count -eq 0 $details = if ($result) { "All Safe Links policies are correctly configured." } else { $misconfiguredDetails -join ' | ' } $failureReasons = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" } diff --git a/source/tests/Test-SpamPolicyAdminNotify.ps1 b/source/tests/Test-SpamPolicyAdminNotify.ps1 index 8f100c7..314d6fd 100644 --- a/source/tests/Test-SpamPolicyAdminNotify.ps1 +++ b/source/tests/Test-SpamPolicyAdminNotify.ps1 @@ -11,23 +11,41 @@ function Test-SpamPolicyAdminNotify { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed - $auditResult = [CISAuditResult]::new() $recnum = "2.1.6" + + <# + Conditions for 2.1.6 (L1) Ensure Exchange Online Spam Policies are set to notify administrators + + Validate recommendation details: + - Confirm that the recommendation details are accurate and complete as per the CIS benchmark. + + Validate test for a pass: + - Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark. + - Specific conditions to check: + - Condition A: In the Microsoft 365 Security & Compliance Center, the Exchange Online Spam Policies are set to notify administrators when a sender in the organization has been blocked for sending spam emails. + - Condition B: Using PowerShell, the `NotifyOutboundSpam` and `NotifyOutboundSpamContact` properties are correctly set in all relevant spam filter policies. + + Validate test for a fail: + - Confirm that the failure conditions in the automated test are consistent with the manual audit results. + - Specific conditions to check: + - Condition A: In the Microsoft 365 Security & Compliance Center, the Exchange Online Spam Policies are not set to notify administrators when a sender in the organization has been blocked for sending spam emails. + - Condition B: Using PowerShell, the `NotifyOutboundSpam` and `NotifyOutboundSpamContact` properties are not correctly set in all relevant spam filter policies. + #> } process { try { # 2.1.6 Ensure Exchange Online Spam Policies are set to notify administrators - # Get the default hosted outbound spam filter policy + # Retrieve the default hosted outbound spam filter policy $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy | Where-Object { $_.IsDefault -eq $true } - # Check if both settings are enabled + # Check if both settings are enabled (Condition A and Condition B for pass) $bccSuspiciousOutboundMailEnabled = $hostedOutboundSpamFilterPolicy.BccSuspiciousOutboundMail $notifyOutboundSpamEnabled = $hostedOutboundSpamFilterPolicy.NotifyOutboundSpam $areSettingsEnabled = $bccSuspiciousOutboundMailEnabled -and $notifyOutboundSpamEnabled - # Prepare failure details if any setting is not enabled + # Prepare failure details if any setting is not enabled (Condition A and Condition B for fail) $failureDetails = @() if (-not $bccSuspiciousOutboundMailEnabled) { $failureDetails += "BccSuspiciousOutboundMail is not enabled." @@ -65,3 +83,4 @@ function Test-SpamPolicyAdminNotify { return $auditResult } } +