From 70218b6c46a68b8b3c722f1051bb422e3d361a57 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Thu, 5 Feb 2026 14:00:24 +0100 Subject: [PATCH 01/20] feat: add CIS 5.1.5.2 test --- powershell/Maester.psd1 | 2 +- .../Test-MtCisAdminConsentWorkflowEnabled.md | 21 +++++++ .../Test-MtCisAdminConsentWorkflowEnabled.ps1 | 62 +++++++++++++++++++ ...MtCisAdminConsentWorkflowEnabled.Tests.ps1 | 10 +++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md create mode 100644 powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 create mode 100644 tests/cis/Test-MtCisAdminConsentWorkflowEnabled.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 2f2cac855..b74fb9018 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -105,7 +105,7 @@ 'Test-MtCaLicenseUtilization', 'Test-MtCaMfaForAdmin', 'Test-MtCaMfaForAdminManagement', 'Test-MtCaMfaForAllUsers', 'Test-MtCaMfaForGuest', 'Test-MtCaMfaForRiskySignIn', 'Test-MtCaMisconfiguredIDProtection', 'Test-MtCaReferencedGroupsExist', 'Test-MtCaReferencedObjectsExist', 'Test-MtCaRequirePasswordChangeForHighUserRisk', - 'Test-MtCaSecureSecurityInfoRegistration', 'Test-MtCaWIFBlockLegacyAuthentication', 'Test-MtCis365PublicGroup', + 'Test-MtCaSecureSecurityInfoRegistration', 'Test-MtCaWIFBlockLegacyAuthentication', 'Test-MtCis365PublicGroup', 'Test-MtCisAdminConsentWorkflowEnabled', 'Test-MtCisAuditLogSearch', 'Test-MtCisAttachmentFilter', 'Test-MtCisAttachmentFilterComprehensive', 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', diff --git a/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md new file mode 100644 index 000000000..03b67e7c9 --- /dev/null +++ b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md @@ -0,0 +1,21 @@ +5.1.5.2 (L1) Ensure the admin consent workflow is enabled + +**Rationale:** +The admin consent workflow (Preview) gives admins a secure way to grant access to applications that require admin approval. When a user tries to access an application but is unable to provide consent, they can send a request for admin approval. The request is sent via email to admins who have been designated as reviewers. A reviewer acts on the request, and the user is notified of the action. + +#### Remediation action: + +1. Navigate to Microsoft Entra ID admin center [https://entra.microsoft.com](https://entra.microsoft.com). +2. Under **Entra ID** select **Enterprise apps** +3. Under **Security** select **Consent and permissions** +4. Under **Manage** select **Admin consent settings** +5. Set **Users can request admin consent to apps they are unable to consent to** to **Yes** +6. Click Save. + +#### Related links + +* [Microsoft 365 Entra Admin Center](https://entra.microsoft.com) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 187](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 new file mode 100644 index 000000000..c5bf64b91 --- /dev/null +++ b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 @@ -0,0 +1,62 @@ +<# +.SYNOPSIS + Checks if the admin consent workflow is enabled + +.DESCRIPTION + The admin consent workflow should be enabled. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisAdminConsentWorkflowEnabled + + Returns true if admin consent workflow is enabled + +.LINK + https://maester.dev/docs/commands/Test-MtCisAdminConsentWorkflowEnabled +#> +function Test-MtCisAdminConsentWorkflowEnabled { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $settings = Invoke-MtGraphRequest -RelativeUri "policies/adminConsentRequestPolicy" -DisableCache + + Write-Verbose 'Executing checks' + $checkAdminConsentWorkflowEnabled = $settings | Where-Object { $_.isEnabled -eq $true } + + $testResult = (($checkAdminConsentWorkflowEnabled | Measure-Object).Count -eq 1) + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenants settings matches CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenants settings does not matches CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($checkAdminConsentWorkflowEnabled) { + $checkAdminConsentWorkflowEnabledResult = '✅ Pass' + } else { + $checkAdminConsentWorkflowEnabledResult = '❌ Fail' + } + + $resultMd += "| Users can request admin consent to apps they are unable to consent to | $checkAdminConsentWorkflowEnabledResult |`n" + + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisAdminConsentWorkflowEnabled.Tests.ps1 b/tests/cis/Test-MtCisAdminConsentWorkflowEnabled.Tests.ps1 new file mode 100644 index 000000000..a2c5ceab2 --- /dev/null +++ b/tests/cis/Test-MtCisAdminConsentWorkflowEnabled.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.5.1.5.2", "L1", "CIS E3 Level 1", "CIS E3", "CIS E5 Level 1", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.5.1.5.2: Ensure the admin consent workflow is enabled" { + + $result = Test-MtCisAdminConsentWorkflowEnabled + + if ($null -ne $result) { + $result | Should -Be $true -Because "admin consent workflow is enabled" + } + } +} \ No newline at end of file From 4f9fe53e31bf019184a53cb26c78af13e55abcd6 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Thu, 5 Feb 2026 14:31:18 +0100 Subject: [PATCH 02/20] feat: add CIS 5.1.2.3 test --- powershell/Maester.psd1 | 2 +- .../cis/Test-MtCisCreateTenantDisallowed.md | 21 +++++++ .../cis/Test-MtCisCreateTenantDisallowed.ps1 | 61 +++++++++++++++++++ ...Test-MtCisCreateTenantDisallowed.Tests.ps1 | 10 +++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisCreateTenantDisallowed.md create mode 100644 powershell/public/cis/Test-MtCisCreateTenantDisallowed.ps1 create mode 100644 tests/cis/Test-MtCisCreateTenantDisallowed.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index b74fb9018..785cdd994 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -107,7 +107,7 @@ 'Test-MtCaReferencedGroupsExist', 'Test-MtCaReferencedObjectsExist', 'Test-MtCaRequirePasswordChangeForHighUserRisk', 'Test-MtCaSecureSecurityInfoRegistration', 'Test-MtCaWIFBlockLegacyAuthentication', 'Test-MtCis365PublicGroup', 'Test-MtCisAdminConsentWorkflowEnabled', 'Test-MtCisAuditLogSearch', 'Test-MtCisAttachmentFilter', 'Test-MtCisAttachmentFilterComprehensive', - 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', + 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', 'Test-MtCisCreateTenantDisallowed', 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', 'Test-MtCisDkim', 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', diff --git a/powershell/public/cis/Test-MtCisCreateTenantDisallowed.md b/powershell/public/cis/Test-MtCisCreateTenantDisallowed.md new file mode 100644 index 000000000..29ceadd09 --- /dev/null +++ b/powershell/public/cis/Test-MtCisCreateTenantDisallowed.md @@ -0,0 +1,21 @@ +5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes' + +**Rationale:** +Restricting tenant creation prevents unauthorized or uncontrolled deployment of resources and ensures that the organization retains control over its infrastructure. +User generation of shadow IT could lead to multiple, disjointed environments that can make it difficult for IT to manage and secure the organization's data, especially if other users in the organization began using these tenants for business purposes under the misunderstanding that they were secured by the organization's security team. + +#### Remediation action: + +1. Navigate to Microsoft 365 Entra admin center [https://entra.microsoft.com](https://entra.microsoft.com). +2. Click to expand **Identity** select **Users**. +3. Click **User settings** +4. Set **Restrict non-admin users from creating tenants** to **Yes** +5. Click Save. + +#### Related links + +* [Microsoft Entra admin center | Users | User settings](https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserManagementMenuBlade/~/UserSettings/menuId/) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 167](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisCreateTenantDisallowed.ps1 b/powershell/public/cis/Test-MtCisCreateTenantDisallowed.ps1 new file mode 100644 index 000000000..d176765e8 --- /dev/null +++ b/powershell/public/cis/Test-MtCisCreateTenantDisallowed.ps1 @@ -0,0 +1,61 @@ +<# +.SYNOPSIS + Checks if non-admin users are restricted from creating tenants + +.DESCRIPTION + Non-admin users should be restricted from creating tenants. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisCreateTenantDisallowed + + Returns true if non-admin users are restricted from creating tenants. + +.LINK + https://maester.dev/docs/commands/Test-MtCisCreateTenantDisallowed +#> +function Test-MtCisCreateTenantDisallowed { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $settings = (Invoke-MtGraphRequest -RelativeUri "policies/authorizationPolicy").defaultUserRolePermissions + + Write-Verbose 'Executing checks' + $checkAllowedToCreateTenants = $settings | Where-Object { $_.allowedToCreateTenants -eq $false } + + $testResult = (($checkAllowedToCreateTenants | Measure-Object).Count -ge 1) + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($checkAllowedToCreateTenants) { + $checkAllowedToCreateTenantsResult = '✅ Pass' + } else { + $checkAllowedToCreateTenantsResult = '❌ Fail' + } + + $resultMd += "| Restrict non-admin users from creating tenants | $checkAllowedToCreateTenantsResult |`n" + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisCreateTenantDisallowed.Tests.ps1 b/tests/cis/Test-MtCisCreateTenantDisallowed.Tests.ps1 new file mode 100644 index 000000000..18d91e243 --- /dev/null +++ b/tests/cis/Test-MtCisCreateTenantDisallowed.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.5.1.2.3", "L1", "CIS E3 Level 1", "CIS E3", "CIS E5 Level 1", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.5.1.2.3: Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'" { + + $result = Test-MtCisCreateTenantDisallowed + + if ($null -ne $result) { + $result | Should -Be $true -Because "users are not allowed to register new tenants." + } + } +} \ No newline at end of file From 653811ba6fc00912ff18bf999ac0e3b96fec505e Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Thu, 5 Feb 2026 14:34:07 +0100 Subject: [PATCH 03/20] fix: CIS 5.1.5.2 markdown --- .../public/cis/Test-MtCisAdminConsentWorkflowEnabled.md | 2 +- .../public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md index 03b67e7c9..770ffca7f 100644 --- a/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md +++ b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.md @@ -14,7 +14,7 @@ The admin consent workflow (Preview) gives admins a secure way to grant access t #### Related links -* [Microsoft 365 Entra Admin Center](https://entra.microsoft.com) +* [Microsoft Entra admin center | Enterprise apps | Consent and permissions | Admin consent settings](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/~/AdminConsentSettings) * [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 187](https://www.cisecurity.org/benchmark/microsoft_365) diff --git a/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 index c5bf64b91..8586f89da 100644 --- a/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 +++ b/powershell/public/cis/Test-MtCisAdminConsentWorkflowEnabled.ps1 @@ -34,9 +34,9 @@ function Test-MtCisAdminConsentWorkflowEnabled { $testResult = (($checkAdminConsentWorkflowEnabled | Measure-Object).Count -eq 1) if ($testResult) { - $testResultMarkdown = "Well done. Your tenants settings matches CIS recommendations.`n`n%TestResult%" + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" } else { - $testResultMarkdown = "Your tenants settings does not matches CIS recommendations.`n`n%TestResult%" + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" } $resultMd = "| Setting | Result |`n" From 1675b5aac1e9c0be059cbebc18f7c716942b4367 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 07:05:12 +0100 Subject: [PATCH 04/20] feat: add CIS 4.1 test --- powershell/Maester.psd1 | 2 +- ...CisDevicesWithoutCompliancePolicyMarked.md | 21 +++++++++ ...isDevicesWithoutCompliancePolicyMarked.ps1 | 47 +++++++++++++++++++ ...cesWithoutCompliancePolicyMarked.Tests.ps1 | 10 ++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md create mode 100644 powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 create mode 100644 tests/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 785cdd994..aa1ef7fee 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -108,7 +108,7 @@ 'Test-MtCaSecureSecurityInfoRegistration', 'Test-MtCaWIFBlockLegacyAuthentication', 'Test-MtCis365PublicGroup', 'Test-MtCisAdminConsentWorkflowEnabled', 'Test-MtCisAuditLogSearch', 'Test-MtCisAttachmentFilter', 'Test-MtCisAttachmentFilterComprehensive', 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', 'Test-MtCisCreateTenantDisallowed', - 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', + 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', 'Test-MtCisDevicesWithoutCompliancePolicyMarked', 'Test-MtCisDkim', 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', diff --git a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md new file mode 100644 index 000000000..31b131c5d --- /dev/null +++ b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md @@ -0,0 +1,21 @@ +4.1 (L2) Ensure devices without a compliance policy are marked 'not compliant' + +**Rationale:** +Implementing this setting is a first step in adopting compliance policies for devices. +When used in together with Conditional Access policies the attack surface can be reduced by forcing an action to be taken for non-compliant devices. + +#### Remediation action: + +To enable notifications for internal users sending malware: +1. Navigate to Microsoft Intune admin center [https://intune.microsoft.com](https://intune.microsoft.com). +2. Click on **Devices** and then unter **Managed devices** on **Compliance**. +3. Click **Compliance settings**. +4. Ensure **Mark devices with no compliance policy assigned as** set to **Not compliant** + +#### Related links + +* [Microsoft Intune Admin Center | Devices | Compliance](https://intune.microsoft.com/#view/Microsoft_Intune_DeviceSettings/DevicesMenu/~/compliance) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 156](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 new file mode 100644 index 000000000..e4c6c727f --- /dev/null +++ b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 @@ -0,0 +1,47 @@ +#Needed Graph Permission: OrgSettings-AppsAndServices.Read.All +function Test-MtCisDevicesWithoutCompliancePolicyMarked { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting "User owned apps and services" settings...' + $settings = Invoke-MtGraphRequest -RelativeUri "deviceManagement/settings" -DisableCache + + Write-Verbose 'Executing checks' + $checkSecureByDefault = $settings | Where-Object { $_.secureByDefault -eq $true } + + $testResult = (($checkSecureByDefault | Measure-Object).Count -ge 1) + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($checkSecureByDefault) { + $checkSecureByDefaultResult = '✅ Pass' + } else { + $checkSecureByDefaultResult = '❌ Fail' + } + + $resultMd += "| Mark devices with no compliance policy assigned as | $checkSecureByDefaultResult |`n" + + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.Tests.ps1 b/tests/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.Tests.ps1 new file mode 100644 index 000000000..3111c972c --- /dev/null +++ b/tests/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.4.1", "L2", "CIS E3 Level 2", "CIS E3", "CIS E5 Level 2", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.4.1: Ensure devices without a compliance policy are marked 'not compliant'" { + + $result = Test-MtCisDevicesWithoutCompliancePolicyMarked + + if ($null -ne $result) { + $result | Should -Be $true -Because "devices without a compliance policy are marked 'not compliant'" + } + } +} \ No newline at end of file From c0b63840d6cf235780d3a6f2ae3b6c1910313c66 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 07:25:29 +0100 Subject: [PATCH 05/20] feat: add CIS 5.1.6.2 test --- powershell/Maester.psd1 | 2 +- .../Test-MtCisEnsureGuestAccessRestricted.md | 19 ++++++++++++ .../Test-MtCisEnsureGuestAccessRestricted.ps1 | 29 +++++++++++++++++++ ...MtCisEnsureGuestAccessRestricted.Tests.ps1 | 10 +++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.md create mode 100644 powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 create mode 100644 tests/cis/Test-MtCisEnsureGuestAccessRestricted.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index aa1ef7fee..129704192 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -109,7 +109,7 @@ 'Test-MtCisAuditLogSearch', 'Test-MtCisAttachmentFilter', 'Test-MtCisAttachmentFilterComprehensive', 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', 'Test-MtCisCreateTenantDisallowed', 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', 'Test-MtCisDevicesWithoutCompliancePolicyMarked', - 'Test-MtCisDkim', 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', + 'Test-MtCisDkim', 'Test-MtCisEnsureGuestAccessRestricted', 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', diff --git a/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.md b/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.md new file mode 100644 index 000000000..72bad832d --- /dev/null +++ b/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.md @@ -0,0 +1,19 @@ +5.1.6.2 (L1) Ensure that guest user access is restricted + +**Rationale:** +By limiting guest access to the most restrictive state this helps prevent malicious group and user object enumeration in the Microsoft 365 environment. This first step, known as reconnaissance in The Cyber Kill Chain, is often conducted by attackers prior to more advanced targeted attacks. + +#### Remediation action: + +1. Navigate to Microsoft Entra ID admin center [https://entra.microsoft.com](https://entra.microsoft.com). +2. Under **Entra ID** select **External Identities** +3. Select **External collaboration settings** +4. Under **Guest user access** set **Guest user access restrictions** to one of the following: + - **Guest users have limited access to properties and memberships of directory objects** + - **Guest user access is restricted to properties and memberships of their own directory objects (most restrictive)** +5. Click Save. + +#### Related links + +* [Microsoft 365 Entra Admin Center | External Identities | External collaboration settings](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/CompanyRelationshipsMenuBlade/~/Settings/menuId/ExternalIdentitiesGettingStarted) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 193](https://www.cisecurity.org/benchmark/microsoft_365) \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 b/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 new file mode 100644 index 000000000..81ed3a435 --- /dev/null +++ b/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 @@ -0,0 +1,29 @@ +function Test-MtCisEnsureGuestAccessRestricted { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $settings = Invoke-MtGraphRequest -RelativeUri "policies/authorizationPolicy" -DisableCache + + $testResult = $settings.guestUserRoleId -eq "10dae51f-b6af-4016-8d66-8c2a99b929b3" -or $settings.guestUserRoleId -eq "2af84b1e-32c8-42b7-82bc-daa82404023b" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations." + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations." + } + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisEnsureGuestAccessRestricted.Tests.ps1 b/tests/cis/Test-MtCisEnsureGuestAccessRestricted.Tests.ps1 new file mode 100644 index 000000000..3056d1f6a --- /dev/null +++ b/tests/cis/Test-MtCisEnsureGuestAccessRestricted.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.5.1.6.2", "L1", "CIS E3 Level 1", "CIS E3", "CIS E5 Level 1", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.5.1.6.2: Ensure that guest user access is restricted" { + + $result = Test-MtCisEnsureGuestAccessRestricted + + if ($null -ne $result) { + $result | Should -Be $true -Because "guest user access is restricted." + } + } +} \ No newline at end of file From beae42b795d2eda2dcd4afb4b15c193ac5058e93 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 07:28:34 +0100 Subject: [PATCH 06/20] feat: add CIS 5.2.3.5 test --- powershell/Maester.psd1 | 2 +- ...-MtCisWeakAuthenticationMethodsDisabled.md | 19 ++++++ ...MtCisWeakAuthenticationMethodsDisabled.ps1 | 61 +++++++++++++++++++ ...eakAuthenticationMethodsDisabled.Tests.ps1 | 10 +++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.md create mode 100644 powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 create mode 100644 tests/cis/Test-MtCisWeakAuthenticationMethodsDisabled.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 129704192..4355662b6 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -114,7 +114,7 @@ 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', 'Test-MtCisTeamsReportSecurityConcerns', 'Test-MtCisThirdPartyAndCustomApps', 'Test-MtCisThirdPartyFileSharing', - 'Test-MtCisZAP', + 'Test-MtCisWeakAuthenticationMethodsDisabled', 'Test-MtCisZAP', 'Test-MtCisaDkim', 'Test-MtCisaActivationNotification', 'Test-MtCisaAntiSpamAllowList', 'Test-MtCisaAntiSpamSafeList', 'Test-MtCisaAppAdminConsent', 'Test-MtCisaAppGroupOwnerConsent', 'Test-MtCisaAppRegistration', 'Test-MtCisaAppUserConsent', 'Test-MtCisaAssignmentNotification', diff --git a/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.md b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.md new file mode 100644 index 000000000..44720e19e --- /dev/null +++ b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.md @@ -0,0 +1,19 @@ +5.2.3.5 (L1) Ensure weak authentication methods are disabled + +**Rationale:** +The SMS and Voice call methods are vulnerable to SIM swapping which could allow an attacker to gain access to your Microsoft 365 account. + +#### Remediation action: + +1. Navigate to Microsoft Entra ID admin center [https://entra.microsoft.com](https://entra.microsoft.com). +2. Under **Entra ID** select **Authentication methods** +3. Under **Manage** select **Policies** +4. Ensure that **SMS**, **Voice call** and **Email OTP** are disabled + +#### Related links + +* [Microsoft 365 Entra admin Center | Authentication methods | Policies](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/AuthenticationMethodsMenuBlade/~/AdminAuthMethods/fromNav/) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 259](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 new file mode 100644 index 000000000..7786ecfdd --- /dev/null +++ b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 @@ -0,0 +1,61 @@ +function Test-MtCisWeakAuthenticationMethodsDisabled { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $settings = Invoke-MtGraphRequest -RelativeUri "policies/authenticationMethodsPolicy" -DisableCache + + Write-Verbose 'Executing checks' + $checkSms = ($settings.authenticationMethodConfigurations | Where-Object { $_.id -eq "Sms" }).State -eq "disabled" + $checkVoice = ($settings.authenticationMethodConfigurations | Where-Object { $_.id -eq "Voice" }).State -eq "disabled" + $checkEmail = ($settings.authenticationMethodConfigurations | Where-Object { $_.id -eq "Email" }).State -eq "disabled" + + $testResult = $checkSms -eq $true -and $checkVoice -eq $true -and $checkEmail -eq $true + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenants settings matches CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenants settings does not matches CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Authentication method | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($checkSms) { + $checkSmsResult = '✅ Pass' + } else { + $checkSmsResult = '❌ Fail' + } + + if ($checkVoice) { + $checkVoiceResult = '✅ Pass' + } else { + $checkVoiceResult = '❌ Fail' + } + + if ($checkEmail) { + $checkEmailResult = '✅ Pass' + } else { + $checkEmailResult = '❌ Fail' + } + + $resultMd += "| SMS | $checkSmsResult |`n" + $resultMd += "| Voice call | $checkVoiceResult |`n" + $resultMd += "| Email OTP | $checkEmailResult |`n" + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisWeakAuthenticationMethodsDisabled.Tests.ps1 b/tests/cis/Test-MtCisWeakAuthenticationMethodsDisabled.Tests.ps1 new file mode 100644 index 000000000..52c2eb60f --- /dev/null +++ b/tests/cis/Test-MtCisWeakAuthenticationMethodsDisabled.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.5.2.3.5", "L1", "CIS E3 Level 1", "CIS E3", "CIS E5 Level 1", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.5.2.3.5: Ensure weak authentication methods are disabled" { + + $result = Test-MtCisWeakAuthenticationMethodsDisabled + + if ($null -ne $result) { + $result | Should -Be $true -Because "weak authentication methods are disabled." + } + } +} \ No newline at end of file From b3cf57b4d388016d67bb57d884e88c33482cfccb Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 07:38:41 +0100 Subject: [PATCH 07/20] feat: add CIS 1.3.4 test --- powershell/Maester.psd1 | 2 +- .../cis/Test-MtCisUserOwnedAppsRestricted.md | 22 +++++++ .../cis/Test-MtCisUserOwnedAppsRestricted.ps1 | 60 +++++++++++++++++++ ...est-MtCisUserOwnedAppsRestricted.Tests.ps1 | 10 ++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.md create mode 100644 powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 create mode 100644 tests/cis/Test-MtCisUserOwnedAppsRestricted.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 4355662b6..732d478ef 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -114,7 +114,7 @@ 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', 'Test-MtCisTeamsReportSecurityConcerns', 'Test-MtCisThirdPartyAndCustomApps', 'Test-MtCisThirdPartyFileSharing', - 'Test-MtCisWeakAuthenticationMethodsDisabled', 'Test-MtCisZAP', + 'Test-MtCisUserOwnedAppsRestricted', 'Test-MtCisWeakAuthenticationMethodsDisabled', 'Test-MtCisZAP', 'Test-MtCisaDkim', 'Test-MtCisaActivationNotification', 'Test-MtCisaAntiSpamAllowList', 'Test-MtCisaAntiSpamSafeList', 'Test-MtCisaAppAdminConsent', 'Test-MtCisaAppGroupOwnerConsent', 'Test-MtCisaAppRegistration', 'Test-MtCisaAppUserConsent', 'Test-MtCisaAssignmentNotification', diff --git a/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.md b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.md new file mode 100644 index 000000000..d197cf69b --- /dev/null +++ b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.md @@ -0,0 +1,22 @@ +1.3.4 (L1) Ensure 'User owned apps and services' is restricted + +**Rationale:** +Attackers commonly use vulnerable and custom-built add-ins to access data in user applications. +While allowing users to install add-ins by themselves does allow them to easily acquire useful add-ins that integrate with Microsoft applications, it can represent a risk if not used and monitored carefully. +Disable future user's ability to install add-ins in Microsoft Word, Excel, or PowerPoint helps reduce your threat-surface and mitigate this risk. + +#### Remediation action: + +1. Navigate to Microsoft 365 admin center [https://admin.microsoft.com](https://admin.microsoft.com). +2. Click to expand **Settings** select **Org settings**. +3. In **Services** select **User owned apps and services.** +4. Uncheck **Let users access the Office Store** and **Let users start trials on behalf of your organization** +5. Click Save. + +#### Related links + +* [Microsoft 365 admin center | Settings | Org settings | User owned apps and services](https://admin.cloud.microsoft/?#/Settings/Services/:/Settings/L1/Store) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 54](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 new file mode 100644 index 000000000..1bff1280b --- /dev/null +++ b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 @@ -0,0 +1,60 @@ +function Test-MtCisUserOwnedAppsRestricted { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + $scopes = (Get-MgContext).Scopes + $permissionMissing = "OrgSettings-AppsAndServices.Read.All" -notin $scopes + if($permissionMissing){ + Add-MtTestResultDetail -SkippedBecause Custom -SkippedCustomReason "Missing Scope OrgSettings-AppsAndServices.Read.All" + return $null + } + + try { + Write-Verbose 'Getting "User owned apps and services" settings...' + $settings = Invoke-MtGraphRequest -ApiVersion beta -RelativeUri "admin/appsAndServices/settings" -DisableCache + + Write-Verbose 'Executing checks' + $CheckIsOfficeStoreEnabled = $settings | Where-Object { $_.isOfficeStoreEnabled -eq $false } + $CheckIsAppAndServicesTrialEnabled = $settings | Where-Object { $_.isAppAndServicesTrialEnabled -eq $false } + + $testResult = (($CheckIsOfficeStoreEnabled | Measure-Object).Count -ge 1) -and (($CheckIsAppAndServicesTrialEnabled | Measure-Object).Count -ge 1) + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($CheckIsOfficeStoreEnabled) { + $CheckIsOfficeStoreEnabledResult = '✅ Pass' + } else { + $CheckIsOfficeStoreEnabledResult = '❌ Fail' + } + + if ($CheckIsAppAndServicesTrialEnabled) { + $CheckIsAppAndServicesTrialEnabledResult = '✅ Pass' + } else { + $CheckIsAppAndServicesTrialEnabledResult = '❌ Fail' + } + + $resultMd += "| Let users access the Office Store | $CheckIsOfficeStoreEnabledResult |`n" + $resultMd += "| Let users start trials on behalf of your organization | $CheckIsAppAndServicesTrialEnabledResult |`n" + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisUserOwnedAppsRestricted.Tests.ps1 b/tests/cis/Test-MtCisUserOwnedAppsRestricted.Tests.ps1 new file mode 100644 index 000000000..7ec1e86fb --- /dev/null +++ b/tests/cis/Test-MtCisUserOwnedAppsRestricted.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.1.3.4", "L1", "CIS E3 Level 1", "CIS E3", "CIS E5 Level 1", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.1.3.4: Ensure 'User owned apps and services' is restricted" { + + $result = Test-MtCisUserOwnedAppsRestricted + + if ($null -ne $result) { + $result | Should -Be $true -Because "'User owned apps and services' is restricted." + } + } +} \ No newline at end of file From 2875b6e2e013e45635468683893e744c0b7236c0 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 07:39:15 +0100 Subject: [PATCH 08/20] fix: CIS 4.1 markdown --- .../public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md | 1 - 1 file changed, 1 deletion(-) diff --git a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md index 31b131c5d..b5a6e515c 100644 --- a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md +++ b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.md @@ -6,7 +6,6 @@ When used in together with Conditional Access policies the attack surface can be #### Remediation action: -To enable notifications for internal users sending malware: 1. Navigate to Microsoft Intune admin center [https://intune.microsoft.com](https://intune.microsoft.com). 2. Click on **Devices** and then unter **Managed devices** on **Compliance**. 3. Click **Compliance settings**. From 12fa7a53b6d7168d6a204a2395c3eb479a03e49d Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 07:39:37 +0100 Subject: [PATCH 09/20] refactor: Change markdown result output --- .../cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 index 7786ecfdd..1d401e058 100644 --- a/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 +++ b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 @@ -20,9 +20,9 @@ $testResult = $checkSms -eq $true -and $checkVoice -eq $true -and $checkEmail -eq $true if ($testResult) { - $testResultMarkdown = "Well done. Your tenants settings matches CIS recommendations.`n`n%TestResult%" + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" } else { - $testResultMarkdown = "Your tenants settings does not matches CIS recommendations.`n`n%TestResult%" + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" } $resultMd = "| Authentication method | Result |`n" From e90bcda42623f396f381741489188608644b4566 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 08:37:52 +0100 Subject: [PATCH 10/20] feat: add CIS 1.3.7 test --- powershell/Maester.psd1 | 2 +- ...tCisThirdPartyStorageServicesRestricted.md | 20 ++++++++ ...CisThirdPartyStorageServicesRestricted.ps1 | 51 +++++++++++++++++++ ...rdPartyStorageServicesRestricted.Tests.ps1 | 10 ++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.md create mode 100644 powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 create mode 100644 tests/cis/Test-MtCisThirdPartyStorageServicesRestricted.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 732d478ef..10793a122 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -114,7 +114,7 @@ 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', 'Test-MtCisTeamsReportSecurityConcerns', 'Test-MtCisThirdPartyAndCustomApps', 'Test-MtCisThirdPartyFileSharing', - 'Test-MtCisUserOwnedAppsRestricted', 'Test-MtCisWeakAuthenticationMethodsDisabled', 'Test-MtCisZAP', + 'Test-MtCisThirdPartyStorageServicesRestricted', 'Test-MtCisUserOwnedAppsRestricted', 'Test-MtCisWeakAuthenticationMethodsDisabled', 'Test-MtCisZAP', 'Test-MtCisaDkim', 'Test-MtCisaActivationNotification', 'Test-MtCisaAntiSpamAllowList', 'Test-MtCisaAntiSpamSafeList', 'Test-MtCisaAppAdminConsent', 'Test-MtCisaAppGroupOwnerConsent', 'Test-MtCisaAppRegistration', 'Test-MtCisaAppUserConsent', 'Test-MtCisaAssignmentNotification', diff --git a/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.md b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.md new file mode 100644 index 000000000..e15b64db0 --- /dev/null +++ b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.md @@ -0,0 +1,20 @@ +1.3.7 (L2) Ensure 'third-party storage services' are restricted in 'Microsoft 365 on the web' + +**Rationale:** +Enabling internal phishing protection for Microsoft Forms will prevent attackers using forms for phishing attacks by asking personal or other sensitive information and URLs. + +#### Remediation action: + +1. Navigate to Microsoft 365 admin center [https://admin.microsoft.com](https://admin.microsoft.com). +2. Click to expand **Settings** select **Org settings**. +3. In **Services** select **Microsoft 365 on the web** +4. Uncheck **Let users open files stored in third-party storage services in Microsoft 365 on the web** +5. Click Save. + +#### Related links + +* [Microsoft 365 admin center | Settings | Org settings | Microsoft 365 on the web](https://admin.cloud.microsoft/?#/Settings/Services/:/Settings/L1/OfficeOnline) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 61](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 new file mode 100644 index 000000000..776cace02 --- /dev/null +++ b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 @@ -0,0 +1,51 @@ +function Test-MtCisThirdPartyStorageServicesRestricted { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $ServicePrincipal = Invoke-MtGraphRequest -RelativeUri "servicePrincipals" -Filter "appId eq 'c1f33bc0-bdb4-4248-ba9b-096807ddb43e'" -DisableCache + + Write-Verbose 'Executing checks' + if ($ServicePrincipal) { + if ($ServicePrincipal.accountEnabled) { + $testResult = $false + } else { + $testResult = $true + } + } else { + $testResult = $false + } + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenants settings matches CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenants settings not matches CIS recommendations`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($testResult) { + $ThirdPartyStorageResult = '✅ Pass' + } else { + $ThirdPartyStorageResult = '❌ Fail' + } + + $resultMd += "| Let users open files stored in third-party storage services in Microsoft 365 on the web | $ThirdPartyStorageResult |`n" + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisThirdPartyStorageServicesRestricted.Tests.ps1 b/tests/cis/Test-MtCisThirdPartyStorageServicesRestricted.Tests.ps1 new file mode 100644 index 000000000..c74ddde12 --- /dev/null +++ b/tests/cis/Test-MtCisThirdPartyStorageServicesRestricted.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.1.3.7", "L2", "CIS E3 Level 2", "CIS E3", "CIS E5 Level 2", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.1.3.7: Ensure 'third-party storage services' are restricted in 'Microsoft 365 on the web'" { + + $result = Test-MtCisThirdPartyStorageServicesRestricted + + if ($null -ne $result) { + $result | Should -Be $true -Because "third-party storage services are restricted." + } + } +} \ No newline at end of file From d5ff6750c8434ee6321e61216a27ffac5346c088 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 08:38:36 +0100 Subject: [PATCH 11/20] refactor: Change markdown result output --- .../cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 index 776cace02..c7926018f 100644 --- a/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 +++ b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 @@ -24,9 +24,9 @@ } if ($testResult) { - $testResultMarkdown = "Well done. Your tenants settings matches CIS recommendations.`n`n%TestResult%" + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" } else { - $testResultMarkdown = "Your tenants settings not matches CIS recommendations`n`n%TestResult%" + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" } $resultMd = "| Setting | Result |`n" From da180ec4b45f893565fd34099735109bd1a366dc Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 08:46:07 +0100 Subject: [PATCH 12/20] feat: add CIS 5.1.2.2 test --- powershell/Maester.psd1 | 2 +- ...t-MtCisThirdPartyApplicationsDisallowed.md | 21 +++++++++ ...-MtCisThirdPartyApplicationsDisallowed.ps1 | 45 +++++++++++++++++++ ...ThirdPartyApplicationsDisallowed.Tests.ps1 | 10 +++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.md create mode 100644 powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 create mode 100644 tests/cis/Test-MtCisThirdPartyApplicationsDisallowed.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 10793a122..69bff5a1e 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -113,7 +113,7 @@ 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', - 'Test-MtCisTeamsReportSecurityConcerns', 'Test-MtCisThirdPartyAndCustomApps', 'Test-MtCisThirdPartyFileSharing', + 'Test-MtCisTeamsReportSecurityConcerns', 'Test-MtCisThirdPartyAndCustomApps', 'Test-MtCisThirdPartyApplicationsDisallowed', 'Test-MtCisThirdPartyFileSharing', 'Test-MtCisThirdPartyStorageServicesRestricted', 'Test-MtCisUserOwnedAppsRestricted', 'Test-MtCisWeakAuthenticationMethodsDisabled', 'Test-MtCisZAP', 'Test-MtCisaDkim', 'Test-MtCisaActivationNotification', 'Test-MtCisaAntiSpamAllowList', 'Test-MtCisaAntiSpamSafeList', 'Test-MtCisaAppAdminConsent', 'Test-MtCisaAppGroupOwnerConsent', diff --git a/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.md b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.md new file mode 100644 index 000000000..058d6656d --- /dev/null +++ b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.md @@ -0,0 +1,21 @@ +5.1.2.2 (L2) Ensure third party integrated applications are not allowed + +**Rationale:** +Third-party integrated applications connection to services should be disabled unless there is a very clear value and robust security controls are in place. +While there are legitimate uses, attackers can grant access from breached accounts to third party applications to exfiltrate data from your tenancy without having to maintain the breached account. + +#### Remediation action: + +1. Navigate to Microsoft 365 Entra admin center [https://entra.microsoft.com](https://entra.microsoft.com). +2. Click to expand **Entra ID** select **Users**. +3. Click **User settings** +4. Set **Users can register applications** to **No** +5. Click Save. + +#### Related links + +* [Microsoft 365 Entra admin Center | Users | User settings](https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserManagementMenuBlade/~/UserSettings/menuId/) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 167](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 new file mode 100644 index 000000000..493e18121 --- /dev/null +++ b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 @@ -0,0 +1,45 @@ +function Test-MtCisThirdPartyApplicationsDisallowed { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $settings = (Invoke-MtGraphRequest -RelativeUri "policies/authorizationPolicy").defaultUserRolePermissions + + Write-Verbose 'Executing checks' + $checkAllowedToCreateApps = $settings | Where-Object { $_.allowedToCreateApps -eq $false } + + $testResult = (($checkAllowedToCreateApps | Measure-Object).Count -ge 1) + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($checkAllowedToCreateApps) { + $checkAllowedToCreateAppsResult = '✅ Pass' + } else { + $checkAllowedToCreateAppsResult = '❌ Fail' + } + + $resultMd += "| Users can register applications | $checkAllowedToCreateAppsResult |`n" + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisThirdPartyApplicationsDisallowed.Tests.ps1 b/tests/cis/Test-MtCisThirdPartyApplicationsDisallowed.Tests.ps1 new file mode 100644 index 000000000..d88d03fda --- /dev/null +++ b/tests/cis/Test-MtCisThirdPartyApplicationsDisallowed.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.5.1.2.2", "L2", "CIS E3 Level 2", "CIS E3", "CIS E5 Level 2", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.5.1.2.2: Ensure third party integrated applications are not allowed" { + + $result = Test-MtCisThirdPartyApplicationsDisallowed + + if ($null -ne $result) { + $result | Should -Be $true -Because "users are not allowed to register third party applications in the tenant." + } + } +} \ No newline at end of file From d262f107e1dc8036113ac452753e58e2dc5d2bb9 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 08:49:55 +0100 Subject: [PATCH 13/20] feat: add CIS 1.3.5 test --- powershell/Maester.psd1 | 2 +- ...est-MtCisFormsPhishingProtectionEnabled.md | 21 ++++++++ ...st-MtCisFormsPhishingProtectionEnabled.ps1 | 52 +++++++++++++++++++ ...isFormsPhishingProtectionEnabled.Tests.ps1 | 10 ++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md create mode 100644 powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 create mode 100644 tests/cis/Test-MtCisFormsPhishingProtectionEnabled.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 69bff5a1e..406253a04 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -109,7 +109,7 @@ 'Test-MtCisAuditLogSearch', 'Test-MtCisAttachmentFilter', 'Test-MtCisAttachmentFilterComprehensive', 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', 'Test-MtCisCreateTenantDisallowed', 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', 'Test-MtCisDevicesWithoutCompliancePolicyMarked', - 'Test-MtCisDkim', 'Test-MtCisEnsureGuestAccessRestricted', 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', + 'Test-MtCisDkim', 'Test-MtCisEnsureGuestAccessRestricted', 'Test-MtCisFormsPhishingProtectionEnabled', 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', diff --git a/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md new file mode 100644 index 000000000..67bf3dae4 --- /dev/null +++ b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md @@ -0,0 +1,21 @@ +1.3.4 (L1) Ensure 'User owned apps and services' is restricted + +**Rationale:** +Enabling internal phishing protection for Microsoft Forms will prevent attackers using forms for phishing attacks by asking personal or other sensitive information and URLs. + +#### Remediation action: + +To enable notifications for internal users sending malware: +1. Navigate to Microsoft 365 admin center [https://admin.microsoft.com](https://admin.microsoft.com). +2. Click to expand **Settings** select **Org settings**. +3. In **Services** select **Microsoft Forms** +4. Check **Add internal phishing protection** under **Phishing protection** +5. Click Save. + +#### Related links + +* [Microsoft 365 Admin Center](https://admin.microsoft.com) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 57](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 new file mode 100644 index 000000000..0d4c3f64c --- /dev/null +++ b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 @@ -0,0 +1,52 @@ +function Test-MtCisFormsPhishingProtectionEnabled { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + $scopes = (Get-MgContext).Scopes + $permissionMissing = "OrgSettings-Forms.Read.All" -notin $scopes + if($permissionMissing){ + Add-MtTestResultDetail -SkippedBecause Custom -SkippedCustomReason "Missing Scope OrgSettings-Forms.Read.All" + return $null + } + + try { + Write-Verbose 'Getting settings...' + $settings = Invoke-MtGraphRequest -ApiVersion beta -RelativeUri "admin/forms/settings" -DisableCache + + Write-Verbose 'Executing checks' + $CheckIsInOrgFormsPhishingScanEnabled = $settings | Where-Object { $_.isInOrgFormsPhishingScanEnabled -eq $true } + + $testResult = (($CheckIsInOrgFormsPhishingScanEnabled | Measure-Object).Count -ge 1) + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($CheckIsInOrgFormsPhishingScanEnabled) { + $CheckIsInOrgFormsPhishingScanEnabledResult = '✅ Pass' + } else { + $CheckIsInOrgFormsPhishingScanEnabledResult = '❌ Fail' + } + + $resultMd += "| Add internal phishing protection | $CheckIsInOrgFormsPhishingScanEnabledResult |`n" + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisFormsPhishingProtectionEnabled.Tests.ps1 b/tests/cis/Test-MtCisFormsPhishingProtectionEnabled.Tests.ps1 new file mode 100644 index 000000000..85407f549 --- /dev/null +++ b/tests/cis/Test-MtCisFormsPhishingProtectionEnabled.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.1.3.5", "L1", "CIS E3 Level 1", "CIS E3", "CIS E5 Level 1", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.1.3.5: Ensure internal phishing protection for Forms is enabled" { + + $result = Test-MtCisFormsPhishingProtectionEnabled + + if ($null -ne $result) { + $result | Should -Be $true -Because "Forms phishing protection is enabled." + } + } +} \ No newline at end of file From 9c560a41218951b25d9429711b2cb9bde31d7505 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 08:54:48 +0100 Subject: [PATCH 14/20] feat: add CIS 5.1.5.1 test --- powershell/Maester.psd1 | 4 +- ...-MtCisEnsureUserConsentToAppsDisallowed.md | 20 +++++++++ ...MtCisEnsureUserConsentToAppsDisallowed.ps1 | 43 +++++++++++++++++++ ...nsureUserConsentToAppsDisallowed.Tests.ps1 | 10 +++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.md create mode 100644 powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 create mode 100644 tests/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 406253a04..306ffb958 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -109,8 +109,8 @@ 'Test-MtCisAuditLogSearch', 'Test-MtCisAttachmentFilter', 'Test-MtCisAttachmentFilterComprehensive', 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', 'Test-MtCisCreateTenantDisallowed', 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', 'Test-MtCisDevicesWithoutCompliancePolicyMarked', - 'Test-MtCisDkim', 'Test-MtCisEnsureGuestAccessRestricted', 'Test-MtCisFormsPhishingProtectionEnabled', 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', - 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', + 'Test-MtCisDkim', 'Test-MtCisEnsureGuestAccessRestricted', 'Test-MtCisEnsureUserConsentToAppsDisallowed', 'Test-MtCisFormsPhishingProtectionEnabled', 'Test-MtCisGlobalAdminCount', + 'Test-MtCisHostedConnectionFilterPolicy', 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', 'Test-MtCisTeamsReportSecurityConcerns', 'Test-MtCisThirdPartyAndCustomApps', 'Test-MtCisThirdPartyApplicationsDisallowed', 'Test-MtCisThirdPartyFileSharing', diff --git a/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.md b/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.md new file mode 100644 index 000000000..418a31c34 --- /dev/null +++ b/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.md @@ -0,0 +1,20 @@ +5.1.5.1 (L2) Ensure user consent to apps accessing company data on their behalf is not allowed + +**Rationale:** +Attackers commonly use custom applications to trick users into granting them access to company data. Restricting user consent mitigates this risk and helps to reduce the threat-surface. + +#### Remediation action: + +1. Navigate to Microsoft 365 Entra admin center [https://entra.microsoft.com](https://entra.microsoft.com). +2. Click to expand **Entra ID** select **Enterprise apps**. +3. Under **Security** click **Consent and permissions** +4. Under **User consent settings** select **Do not allow user consent**. +5. Click **Save** + +#### Related links + +* [Microsoft 365 Entra admin center | Enterprise apps | Consent and permissions | User consent settings](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/~/UserSettings) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 184](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 b/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 new file mode 100644 index 000000000..c9f62f482 --- /dev/null +++ b/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 @@ -0,0 +1,43 @@ +function Test-MtCisEnsureUserConsentToAppsDisallowed { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $settings = (Invoke-MtGraphRequest -RelativeUri "policies/authorizationPolicy" -DisableCache).defaultUserRolePermissions + + Write-Verbose 'Executing checks' + $testResult = $settings.permissionGrantPoliciesAssigned -notcontains "ManagePermissionGrantsForSelf.microsoft-user-default-low" -and $settings.permissionGrantPoliciesAssigned -notcontains "ManagePermissionGrantsForSelf.microsoft-user-default-legacy" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Setting | Result |`n" + $resultMd += "| --- | --- |`n" + + if ($testResult) { + $checkResult = '✅ Pass' + } else { + $checkResult = '❌ Fail' + } + + $resultMd += "| User consent for applications | $checkResult |`n" + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.Tests.ps1 b/tests/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.Tests.ps1 new file mode 100644 index 000000000..b5f29c123 --- /dev/null +++ b/tests/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.5.1.5.1", "L2", "CIS E3 Level 2", "CIS E3", "CIS E5 Level 2", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.5.1.5.1: Ensure user consent to apps accessing company data on their behalf is not allowed" { + + $result = Test-MtCisEnsureUserConsentToAppsDisallowed + + if ($null -ne $result) { + $result | Should -Be $true -Because "user constent to apps accessing company data on their behalf is not allowed." + } + } +} \ No newline at end of file From 539db99c4b0871de42dd4723c3500afc062a7918 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 09:00:45 +0100 Subject: [PATCH 15/20] feat: add CIS 5.1.3.1 test --- powershell/Maester.psd1 | 4 +- .../Test-MtCisEnsureGuestUserDynamicGroup.md | 27 ++++++++++++ .../Test-MtCisEnsureGuestUserDynamicGroup.ps1 | 41 +++++++++++++++++++ ...MtCisEnsureGuestUserDynamicGroup.Tests.ps1 | 10 +++++ 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.md create mode 100644 powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 create mode 100644 tests/cis/Test-MtCisEnsureGuestUserDynamicGroup.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 306ffb958..f6d51fa8a 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -109,8 +109,8 @@ 'Test-MtCisAuditLogSearch', 'Test-MtCisAttachmentFilter', 'Test-MtCisAttachmentFilterComprehensive', 'Test-MtCisCalendarSharing', 'Test-MtCisCloudAdmin', 'Test-MtCisCreateTenantDisallowed', 'Test-MtCisCommunicateWithUnmanagedTeamsUsers', 'Test-MtCisConnectionFilterSafeList', 'Test-MtCisCustomerLockBox', 'Test-MtCisDevicesWithoutCompliancePolicyMarked', - 'Test-MtCisDkim', 'Test-MtCisEnsureGuestAccessRestricted', 'Test-MtCisEnsureUserConsentToAppsDisallowed', 'Test-MtCisFormsPhishingProtectionEnabled', 'Test-MtCisGlobalAdminCount', - 'Test-MtCisHostedConnectionFilterPolicy', 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', + 'Test-MtCisDkim', 'Test-MtCisEnsureGuestAccessRestricted', 'Test-MtCisEnsureGuestUserDynamicGroup', 'Test-MtCisEnsureUserConsentToAppsDisallowed', 'Test-MtCisFormsPhishingProtectionEnabled', + 'Test-MtCisGlobalAdminCount', 'Test-MtCisHostedConnectionFilterPolicy', 'Test-MtCisInternalMalwareNotification', 'Test-MtCisOutboundSpamFilterPolicy', 'Test-MtCisPasswordExpiry', 'Test-MtCisSafeAntiPhishingPolicy', 'Test-MtCisSafeAttachment', 'Test-MtCisSafeAttachmentsAtpPolicy', 'Test-MtCisSafeLink', 'Test-MtCisSharedMailboxSignIn', 'Test-MtCisTeamsLobbyBypass', 'Test-MtCisTeamsReportSecurityConcerns', 'Test-MtCisThirdPartyAndCustomApps', 'Test-MtCisThirdPartyApplicationsDisallowed', 'Test-MtCisThirdPartyFileSharing', diff --git a/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.md b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.md new file mode 100644 index 000000000..b53ded280 --- /dev/null +++ b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.md @@ -0,0 +1,27 @@ +5.1.3.1 (L1) Ensure a dynamic group for guest users is created + +**Rationale:** +Dynamic groups allow for an automated method to assign group membership. +Guest user accounts will be automatically added to this group and through this existing conditional access rules, access controls and other security measures will ensure that new guest accounts are restricted in the same manner as existing guest accounts. + +#### Remediation action: + +1. Navigate to Microsoft 365 Entra admin center [https://entra.microsoft.com](https://entra.microsoft.com). +2. Click to expand **Identity** select **Groups**. +3. Click **All groups** +4. Select **New group** and assign the following values: + - Group type: **Security** + - Microsoft Entra roles can be assigned to the group: **No** + - Membership type: **Dynamic User** +5. Click **Add dynamic query**. +6. Click **Edit** above the Rule Syntax box. +7. Enter `(user.userType -eq "Guest")` +8. Click **OK** and **Save**. + +#### Related links + +* [Microsoft 365 Entra admin center | Groups](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/GroupsManagementMenuBlade/~/Overview/menuId/Overview) +* [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 179](https://www.cisecurity.org/benchmark/microsoft_365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 new file mode 100644 index 000000000..9798a63af --- /dev/null +++ b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 @@ -0,0 +1,41 @@ +function Test-MtCisEnsureGuestUserDynamicGroup { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + try { + Write-Verbose 'Getting settings...' + $groups = Invoke-MtGraphRequest -RelativeUri "groups" -DisableCache | Where-Object { $_.groupTypes -contains "DynamicMembership" } + + Write-Verbose 'Executing checks' + $checkGuestUserGroup = $groups | Where-Object { $_.MembershipRule -like "*(user.userType -eq `"Guest`")*" } + + $testResult = (($checkGuestUserGroup | Measure-Object).Count -ge 1) + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant settings comply with CIS recommendations.`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" + } + + $resultMd = "| Group(s) |`n" + $resultMd += "| --- |`n" + + foreach ($group in $checkGuestUserGroup) { + $resultMd += "| $($group.DisplayName) |`n" + } + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd + + Add-MtTestResultDetail -Result $testResultMarkdown -GraphObjects $checkGuestUserGroup -GraphObjectType Groups + return $testResult + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + return $null + } +} \ No newline at end of file diff --git a/tests/cis/Test-MtCisEnsureGuestUserDynamicGroup.Tests.ps1 b/tests/cis/Test-MtCisEnsureGuestUserDynamicGroup.Tests.ps1 new file mode 100644 index 000000000..a6c1ade09 --- /dev/null +++ b/tests/cis/Test-MtCisEnsureGuestUserDynamicGroup.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CIS" -Tag "CIS.M365.5.1.3.1", "L1", "CIS E3 Level 1", "CIS E3", "CIS E5 Level 1", "CIS E5", "CIS", "Security", "CIS M365 v5.0.0" { + It "CIS.M365.5.1.3.1: Ensure a dynamic group for guest users is created" { + + $result = Test-MtCisEnsureGuestUserDynamicGroup + + if ($null -ne $result) { + $result | Should -Be $true -Because "a dynamic group for Guest users exists." + } + } +} \ No newline at end of file From 6489287187812fd5a0a1017f00d259ef8c5c3a90 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 09:06:56 +0100 Subject: [PATCH 16/20] refactor: Use GraphObjects in test results --- .../public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 | 9 --------- 1 file changed, 9 deletions(-) diff --git a/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 index 9798a63af..2f6395e14 100644 --- a/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 +++ b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 @@ -23,15 +23,6 @@ $testResultMarkdown = "Your tenant settings not comply with CIS recommendations.`n`n%TestResult%" } - $resultMd = "| Group(s) |`n" - $resultMd += "| --- |`n" - - foreach ($group in $checkGuestUserGroup) { - $resultMd += "| $($group.DisplayName) |`n" - } - - $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd - Add-MtTestResultDetail -Result $testResultMarkdown -GraphObjects $checkGuestUserGroup -GraphObjectType Groups return $testResult } catch { From 05ab0054297f2b386475d194cd7c5083fdb0935d Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 09:14:25 +0100 Subject: [PATCH 17/20] fix: use DisableCache --- .../cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 | 2 +- .../public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 | 2 +- powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 index e4c6c727f..9985bc47d 100644 --- a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 +++ b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 @@ -10,7 +10,7 @@ function Test-MtCisDevicesWithoutCompliancePolicyMarked { } try { - Write-Verbose 'Getting "User owned apps and services" settings...' + Write-Verbose 'Getting settings...' $settings = Invoke-MtGraphRequest -RelativeUri "deviceManagement/settings" -DisableCache Write-Verbose 'Executing checks' diff --git a/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 index 493e18121..e383ac89a 100644 --- a/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 +++ b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 @@ -10,7 +10,7 @@ try { Write-Verbose 'Getting settings...' - $settings = (Invoke-MtGraphRequest -RelativeUri "policies/authorizationPolicy").defaultUserRolePermissions + $settings = (Invoke-MtGraphRequest -RelativeUri "policies/authorizationPolicy" -DisableCache).defaultUserRolePermissions Write-Verbose 'Executing checks' $checkAllowedToCreateApps = $settings | Where-Object { $_.allowedToCreateApps -eq $false } diff --git a/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 index 1bff1280b..80580d292 100644 --- a/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 +++ b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 @@ -16,7 +16,7 @@ } try { - Write-Verbose 'Getting "User owned apps and services" settings...' + Write-Verbose 'Getting settings...' $settings = Invoke-MtGraphRequest -ApiVersion beta -RelativeUri "admin/appsAndServices/settings" -DisableCache Write-Verbose 'Executing checks' From 8196bad57230f2dbf3fc1e89cf99206a2e584c7f Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 09:37:32 +0100 Subject: [PATCH 18/20] fix: add missing synopsis blocks --- ...CisDevicesWithoutCompliancePolicyMarked.ps1 | 17 ++++++++++++++++- .../Test-MtCisEnsureGuestAccessRestricted.ps1 | 18 +++++++++++++++++- .../Test-MtCisEnsureGuestUserDynamicGroup.ps1 | 18 +++++++++++++++++- ...-MtCisEnsureUserConsentToAppsDisallowed.ps1 | 18 +++++++++++++++++- ...est-MtCisFormsPhishingProtectionEnabled.ps1 | 18 +++++++++++++++++- ...t-MtCisThirdPartyApplicationsDisallowed.ps1 | 18 +++++++++++++++++- ...tCisThirdPartyStorageServicesRestricted.ps1 | 18 +++++++++++++++++- .../cis/Test-MtCisUserOwnedAppsRestricted.ps1 | 18 +++++++++++++++++- ...-MtCisWeakAuthenticationMethodsDisabled.ps1 | 18 +++++++++++++++++- 9 files changed, 152 insertions(+), 9 deletions(-) diff --git a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 index 9985bc47d..d5789a6f0 100644 --- a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 +++ b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 @@ -1,4 +1,19 @@ -#Needed Graph Permission: OrgSettings-AppsAndServices.Read.All +<# +.SYNOPSIS + Checks if devices without a compliance policy assigned are marked "not compliant". + +.DESCRIPTION + Devices without a compliance policy assigned should be marked "not compliant". + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisDevicesWithoutCompliancePolicyMarked + + Returns true if devices without a compliance policy assigned are marked "not compliant". + +.LINK + https://maester.dev/docs/commands/Test-MtCisDevicesWithoutCompliancePolicyMarked +#> function Test-MtCisDevicesWithoutCompliancePolicyMarked { [CmdletBinding()] [OutputType([bool])] diff --git a/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 b/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 index 81ed3a435..1d6734209 100644 --- a/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 +++ b/powershell/public/cis/Test-MtCisEnsureGuestAccessRestricted.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisEnsureGuestAccessRestricted { +<# +.SYNOPSIS + Checks if guest user access is restricted. + +.DESCRIPTION + Guest user access should be restricted to only necessary resources. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisEnsureGuestAccessRestricted + + Returns true if guest user access is restricted. + +.LINK + https://maester.dev/docs/commands/Test-MtCisEnsureGuestAccessRestricted +#> +function Test-MtCisEnsureGuestAccessRestricted { [CmdletBinding()] [OutputType([bool])] param() diff --git a/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 index 2f6395e14..c0d14ce15 100644 --- a/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 +++ b/powershell/public/cis/Test-MtCisEnsureGuestUserDynamicGroup.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisEnsureGuestUserDynamicGroup { +<# +.SYNOPSIS + Checks if minimum one dynamic group exists with a membership rule targeting guest users. + +.DESCRIPTION + There should be minimum one dynamic group with a membership rule targeting guest users to ensure that guest users are easily identifiable and can be managed effectively. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisEnsureGuestUserDynamicGroup + + Returns true if a group with a membership rule targeting guest users exists. + +.LINK + https://maester.dev/docs/commands/Test-MtCisEnsureGuestUserDynamicGroup +#> +function Test-MtCisEnsureGuestUserDynamicGroup { [CmdletBinding()] [OutputType([bool])] param() diff --git a/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 b/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 index c9f62f482..b4d584032 100644 --- a/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 +++ b/powershell/public/cis/Test-MtCisEnsureUserConsentToAppsDisallowed.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisEnsureUserConsentToAppsDisallowed { +<# +.SYNOPSIS + Checks if user consent to applications is disallowed. + +.DESCRIPTION + Users should not be allowed to consent to applications. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisEnsureUserConsentToAppsDisallowed + + Returns true if users are not allowed to consent to applications. + +.LINK + https://maester.dev/docs/commands/Test-MtCisEnsureUserConsentToAppsDisallowed +#> +function Test-MtCisEnsureUserConsentToAppsDisallowed { [CmdletBinding()] [OutputType([bool])] param() diff --git a/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 index 0d4c3f64c..8467ea8bc 100644 --- a/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 +++ b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisFormsPhishingProtectionEnabled { +<# +.SYNOPSIS + Checks if the internal phishing protection for Microsoft Forms is enabled. + +.DESCRIPTION + The internal phishing protection for Microsoft Forms should be enabled. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisFormsPhishingProtectionEnabled + + Returns true if the internal phishing protection for Microsoft Forms is enabled. + +.LINK + https://maester.dev/docs/commands/Test-MtCisFormsPhishingProtectionEnabled +#> +function Test-MtCisFormsPhishingProtectionEnabled { [CmdletBinding()] [OutputType([bool])] param() diff --git a/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 index e383ac89a..f370eab6c 100644 --- a/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 +++ b/powershell/public/cis/Test-MtCisThirdPartyApplicationsDisallowed.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisThirdPartyApplicationsDisallowed { +<# +.SYNOPSIS + Checks if users are not allowed to register applications. + +.DESCRIPTION + Users should not be allowed to register applications in the tenant. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisThirdPartyApplicationsDisallowed + + Returns true if users are not allowed to register applications in the tenant. + +.LINK + https://maester.dev/docs/commands/Test-MtCisThirdPartyApplicationsDisallowed +#> +function Test-MtCisThirdPartyApplicationsDisallowed { [CmdletBinding()] [OutputType([bool])] param() diff --git a/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 index c7926018f..5685a9746 100644 --- a/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 +++ b/powershell/public/cis/Test-MtCisThirdPartyStorageServicesRestricted.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisThirdPartyStorageServicesRestricted { +<# +.SYNOPSIS + Checks if users are restricted to store and share files in third-party storage services in Microsoft 365 on the web. + +.DESCRIPTION + Users should be restricted to store and share files in third-party storage services in Microsoft 365 on the web. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisThirdPartyStorageServicesRestricted + + Returns true if users are restricted to store and share files in third-party storage services in Microsoft 365 on the web. + +.LINK + https://maester.dev/docs/commands/Test-MtCisThirdPartyStorageServicesRestricted +#> +function Test-MtCisThirdPartyStorageServicesRestricted { [CmdletBinding()] [OutputType([bool])] param() diff --git a/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 index 80580d292..88dd22ce0 100644 --- a/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 +++ b/powershell/public/cis/Test-MtCisUserOwnedAppsRestricted.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisUserOwnedAppsRestricted { +<# +.SYNOPSIS + Checks if users are restricted to install add-ins from the Office Store and start trials on behalf of the organization. + +.DESCRIPTION + Users should be restricted to install add-ins from the Office Store and start trials on behalf of the organization. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisUserOwnedAppsRestricted + + Returns true if users cannot install add-ins from the Office Store and start trials on behalf of the organization. + +.LINK + https://maester.dev/docs/commands/Test-MtCisUserOwnedAppsRestricted +#> +function Test-MtCisUserOwnedAppsRestricted { [CmdletBinding()] [OutputType([bool])] param() diff --git a/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 index 1d401e058..2b9457b9b 100644 --- a/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 +++ b/powershell/public/cis/Test-MtCisWeakAuthenticationMethodsDisabled.ps1 @@ -1,4 +1,20 @@ -function Test-MtCisWeakAuthenticationMethodsDisabled { +<# +.SYNOPSIS + Checks if weak authentication methods (SMS, voice call, email OTP) are disabled in the tenant. + +.DESCRIPTION + Weak authentication methods such as SMS, voice call, and email OTP should be disabled. + CIS Microsoft 365 Foundations Benchmark v5.0.0 + +.EXAMPLE + Test-MtCisWeakAuthenticationMethodsDisabled + + Returns true if weak authentication methods are disabled. + +.LINK + https://maester.dev/docs/commands/Test-MtCisWeakAuthenticationMethodsDisabled +#> +function Test-MtCisWeakAuthenticationMethodsDisabled { [CmdletBinding()] [OutputType([bool])] param() From fd7d140611f5d9bbffb6f5a224ed18db97dc77b8 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 09:49:34 +0100 Subject: [PATCH 19/20] fix: markdown title --- .../public/cis/Test-MtCisFormsPhishingProtectionEnabled.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md index 67bf3dae4..21ed747f8 100644 --- a/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md +++ b/powershell/public/cis/Test-MtCisFormsPhishingProtectionEnabled.md @@ -1,20 +1,19 @@ -1.3.4 (L1) Ensure 'User owned apps and services' is restricted +1.3.5 (L1) Ensure internal phishing protection for Forms is enabled **Rationale:** Enabling internal phishing protection for Microsoft Forms will prevent attackers using forms for phishing attacks by asking personal or other sensitive information and URLs. #### Remediation action: -To enable notifications for internal users sending malware: 1. Navigate to Microsoft 365 admin center [https://admin.microsoft.com](https://admin.microsoft.com). 2. Click to expand **Settings** select **Org settings**. 3. In **Services** select **Microsoft Forms** -4. Check **Add internal phishing protection** under **Phishing protection** +4. Enable **Add internal phishing protection** under **Phishing protection** 5. Click Save. #### Related links -* [Microsoft 365 Admin Center](https://admin.microsoft.com) +* [Microsoft 365 admin center | Settings | Org settings | Microsoft Forms](https://admin.cloud.microsoft/?#/Settings/Services/:/Settings/L1/OfficeForms) * [CIS Microsoft 365 Foundations Benchmark v5.0.0 - Page 57](https://www.cisecurity.org/benchmark/microsoft_365) From 02c6ee7e477520f3a7efdd8208f02176c5091746 Mon Sep 17 00:00:00 2001 From: Benjamin Metz Date: Fri, 6 Feb 2026 09:49:59 +0100 Subject: [PATCH 20/20] refactor: setting name in output --- .../cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 index d5789a6f0..170ca5e8f 100644 --- a/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 +++ b/powershell/public/cis/Test-MtCisDevicesWithoutCompliancePolicyMarked.ps1 @@ -48,7 +48,7 @@ function Test-MtCisDevicesWithoutCompliancePolicyMarked { $checkSecureByDefaultResult = '❌ Fail' } - $resultMd += "| Mark devices with no compliance policy assigned as | $checkSecureByDefaultResult |`n" + $resultMd += "| Mark devices with no compliance policy assigned as 'Not compliant' | $checkSecureByDefaultResult |`n" $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $resultMd