Skip to content

Added CIS M365v5 SPO tests#1433

Closed
HenrikPiecha wants to merge 21 commits into
maester365:mainfrom
HenrikPiecha:CISM365v57-SPO
Closed

Added CIS M365v5 SPO tests#1433
HenrikPiecha wants to merge 21 commits into
maester365:mainfrom
HenrikPiecha:CISM365v57-SPO

Conversation

@HenrikPiecha
Copy link
Copy Markdown
Contributor

Description

Added SharePoint Online admin center tests from CIS Microsoft 365 v5.0.0
All the tests are related to the PowerShell module Microsoft.Online.SharePoint.PowerShell.

@merill please check the invocation as discussed.
The tests with Tag SpoTenant should only be executed when running interactivly as the ps module currently does not support read-only permission or service principal authentication from powershell 7.

Running the connection is mandatory:

Connect-SPOService -Url https://<tenant>-admin.sharepoint.com

Contribution Checklist

Before submitting this PR, please confirm you have completed the following:

  • [x ] 📖 Read the guidelines for contributing to this repository.
  • [ x] 🧪 Ensure the build and unit tests pass by running /powershell/tests/pester.ps1 on your local system.

 

Join us at the Maester repository discussions 💬 or Entra Discord 🧑‍💻 for more help and conversations!

@SamErde
Copy link
Copy Markdown
Contributor

SamErde commented Feb 17, 2026

I'm excited to see these in action, @HenrikPiecha!

As you noted above, these will not work in some contexts. Can you add checks to the beginning of the Pester test for these so it will fail gracefully and return a relevant SkippedBecause reason to the results report? Let us know if you'd like any help with that!

The tests with Tag SpoTenant should only be executed when running interactivly as the ps module currently does not support read-only permission or service principal authentication from powershell 7.

Running the connection is mandatory:

Connect-SPOService -Url https://<tenant>-admin.sharepoint.com

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds 7 new SharePoint Online (SPO) tests based on CIS Microsoft 365 v5.0.0 benchmark recommendations. These tests validate SPO tenant configuration settings related to external sharing, guest access, custom scripts, and malware protection. All tests use the Microsoft.Online.SharePoint.PowerShell module and require interactive connection via Connect-SPOService.

Changes:

  • Added 7 PowerShell test functions (Test-MtSpo*) for SPO tenant security checks
  • Added corresponding Pester tests tagged with 'SpoTenant'
  • Added website and PowerShell documentation for all 7 tests
  • Updated maester-config.json with test metadata (MT.1113-MT.1119)
  • Exported new functions in Maester.psd1 module manifest

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
tests/Maester/Spo/Test-SpoTenant.Tests.ps1 New Pester test file containing 7 SPO tenant configuration tests (MT.1113-MT.1119)
powershell/public/maester/spo/Test-MtSpoB2BIntegration.ps1 Tests Microsoft Entra B2B integration (CIS 7.2.2)
powershell/public/maester/spo/Test-MtSpoCustomScriptExecutionOnSiteCollection.ps1 Tests custom script restrictions on site collections (CIS 7.3.4)
powershell/public/maester/spo/Test-MtSpoDefaultSharingLink.ps1 Tests default sharing link type restrictions (CIS 7.2.7)
powershell/public/maester/spo/Test-MtSpoDefaultSharingLinkPermission.ps1 Tests default sharing link permissions (CIS 7.2.11)
powershell/public/maester/spo/Test-MtSpoGuestAccessExpiry.ps1 Tests guest access expiration settings (CIS 7.2.9)
powershell/public/maester/spo/Test-MtSpoGuestCannotShareUnownedItem.ps1 Tests guest resharing restrictions (CIS 7.2.5)
powershell/public/maester/spo/Test-MtSpoPreventDownloadMaliciousFile.ps1 Tests malicious file download prevention (CIS 7.3.1)
powershell/public/maester/spo/*.md Documentation files for each test function
website/docs/tests/maester/MT.111*.md Website documentation for each test with CIS benchmark details
tests/maester-config.json Configuration entries for all 7 new tests with severity levels
powershell/Maester.psd1 Module manifest updated to export 7 new SPO functions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread powershell/public/maester/spo/Test-MtSpoCustomScriptExecutionOnSiteCollection.ps1 Outdated
Comment thread powershell/public/maester/spo/Test-MtSpoCustomScriptExecutionOnSiteCollection.ps1 Outdated
Comment thread tests/Maester/Spo/Test-SpoTenant.Tests.ps1 Outdated
Comment thread powershell/public/maester/spo/Test-MtSpoDefaultSharingLink.ps1 Outdated
Comment thread powershell/Maester.psd1 Outdated
Comment thread powershell/public/maester/spo/Test-MtSpoB2BIntegration.md Outdated
Comment thread powershell/public/maester/spo/Test-MtSpoGuestAccessExpiry.ps1 Outdated
Comment thread website/docs/tests/maester/MT.1113.md Outdated
Comment thread tests/Maester/Spo/Test-SpoTenant.Tests.ps1 Outdated
Comment thread website/docs/tests/maester/MT.1118.md Outdated
@SamErde SamErde added enhancement New feature or request maester-test Related to a Maester test sharepoint Microsoft SharePoint labels Feb 17, 2026
SamErde and others added 4 commits February 17, 2026 13:13
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@SamErde
Copy link
Copy Markdown
Contributor

SamErde commented Feb 17, 2026

BTW, you do not need to specify a severity tag in the Pester test files if they are added to the maester-config.json file.

@merill
Copy link
Copy Markdown
Contributor

merill commented Feb 18, 2026

@HenrikPiecha one catch I noticed with the SPO cmdlets is they don't work on non Windows devices like macOS.

Do you know if these tests can make use of PnP PowerShell? I believe that module has been updated PS7.

https://learn.microsoft.com/en-us/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets

I believe this would also solve the interactive issue because PnP supports app only as well.

Do you know off the top of your head if these cmdlets are only available in SPO.

Another addition we need to make is to ./website/docs/installation.md and include the SPO (or PnP) module in the optional steps.

If not, folks would never know that they need to connect to SPO/PnP to run thes

@HenrikPiecha
Copy link
Copy Markdown
Contributor Author

@merill I focused on the SharePoint "native" module because, in my opinion, it is easier to use than PnP.

@SamErde I tried adding some logic on the Connect-Maester as well as in the .Tests.ps1 files. Its not perfect but it may be a starting point for discussions :)

@merill
Copy link
Copy Markdown
Contributor

merill commented Apr 1, 2026

@HenrikPiecha are you open to changing these SPO calls on PnP?

Without it these tests are very unlikely to be run by a majority user Maester users that run on GitHub actions since these containers are all Linux. So none of the Windows PowerShell dependent modules like SPO will work.

Thoughts?

If you don't have bandwidth are you okay if I update them to PnP PS?

@merill merill mentioned this pull request Apr 3, 2026
10 tasks
@HenrikPiecha
Copy link
Copy Markdown
Contributor Author

@merill I'll give the PnP Option a try, for now I struggeled with getting this to work with existing App registrations.
As soon as I have it working I'll give you a ping and check how to best integrate it as there are multiple SPO PRs atm.

@HenrikPiecha
Copy link
Copy Markdown
Contributor Author

@merill It really wasn't as complicated as I thought..

The changes I did to Connect-Maester, I would revert to query the tenant domain via graph api "organization" via:

$org = Invoke-MtGraphRequest -RelativeUri "organization"
$tenantDomain  = ($org.verifiedDomains | Where-Object {$_.isInitial -eq $true}) | Select-Object -ExpandProperty Name
$spoUri = "https://$(($tenantDomain).Replace(".onmicrosoft.com",$null))-admin.sharepoint.com"

To connect to PnP it would switch to following for non-interactive login.

Connect-PnPOnline -Url $spoUri -Tenant $tenantDomain -ClientId $GraphClientId  -Thumbprint $CertThumbprint -ErrorAction Stop # CertThumbprint variable unknown?!

For Interactive logins we would require a custom app registration with redirect uri "mobile and desktop applications" listening on "http://localhost" and api permissions "SharePoint > Sites.FullControl.All"

Connect-PnPOnline -Url $spoUri -ClientId $GraphClientId -Interactive

Within all the tests we simply would run "Get-PnPTenant" instead of "Get-SpoTenant", performance wise we could add the results after first execution in a "CmdletCache" and keep on calling from there.

Let me know what you think. Should I add a new PR to start from "scratch"?

Some new tests i have been working on, checking the SharePoint Online default orgwide sharing link expiration that will be GA in the next weeks are currently not working with PnP as I can't query the property.

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Apr 9, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@merill
Copy link
Copy Markdown
Contributor

merill commented Apr 12, 2026

@HenrikPiecha yes let's do this. For the interactive, we don't really need a custom app since we already have the Graph PowerShell app which does have localhost on it.

I believe all we need to do is add the SPO scope when calling connect-graph.

For the ones that are not there, maybe opening an issue in the PnP repo would help us track so we know when its available to then use it in maester...

@Mynster9361
Copy link
Copy Markdown
Contributor

Mynster9361 commented Apr 17, 2026

Just adding a note on this one.
The maester test framework for CIS has been updated to "CIS Microsoft 365 Foundations Benchmark v6.0.1" instead of v5.0.0.

Looking at the Appendix: Change History in the document there is the following updates/changes to Chapter 7

REMOVE - 7.3.3 (L1) Ensure custom script execution is restricted on personal sites - Setting now unavailable in SharePoint
Ticket #25452

REMOVE - 7.3.4 (L1) Ensure custom script execution is restricted on site collections - Property is automatically disabled by MS after 24 hours
Ticket #25741

UPDATE - 7.2.6 (L2) Ensure SharePoint external sharing is restricted - New title, clarify title, description and audit procedure
Ticket #23794

@SamErde
Copy link
Copy Markdown
Contributor

SamErde commented Apr 17, 2026

Just adding a note on this one. The maester test framework for CIS has been updated to "CIS Microsoft 365 Foundations Benchmark v6.0.1" instead of v5.0.0.

Looking at the Appendix: Change History in the document there is the following updates/changes to Chapter 7

REMOVE - 7.3.3 (L1) Ensure custom script execution is restricted on personal sites - Setting now unavailable in SharePoint
Ticket #25452

REMOVE - 7.3.4 (L1) Ensure custom script execution is restricted on site collections - Property is automatically disabled by MS after 24 hours
Ticket #25741

UPDATE - 7.2.6 (L2) Ensure SharePoint external sharing is restricted - New title, clarify title, description and audit procedure
Ticket #23794

So are those all tests that can be removed or updated in our version?

@Mynster9361
Copy link
Copy Markdown
Contributor

Just adding a note on this one. The maester test framework for CIS has been updated to "CIS Microsoft 365 Foundations Benchmark v6.0.1" instead of v5.0.0.
Looking at the Appendix: Change History in the document there is the following updates/changes to Chapter 7

REMOVE - 7.3.3 (L1) Ensure custom script execution is restricted on personal sites - Setting now unavailable in SharePoint
Ticket #25452

REMOVE - 7.3.4 (L1) Ensure custom script execution is restricted on site collections - Property is automatically disabled by MS after 24 hours
Ticket #25741

UPDATE - 7.2.6 (L2) Ensure SharePoint external sharing is restricted - New title, clarify title, description and audit procedure
Ticket #23794

So are those all tests that can be removed or updated in our version?

I can see none of the tests with changes 7.3.3, 7.3.4, 7.2.6 is included in this PR so my comments can be ignored :D

But if 7.3.3, 7.3.4 was in it they could be removed and 7.2.6 would have needed an update for docs & maybe title and then validate the audit logic

SamErde and others added 6 commits April 29, 2026 07:07
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…dItem.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…dItem.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…usFile.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread powershell/public/Connect-Maester.ps1 Outdated
Comment thread powershell/public/Connect-Maester.ps1
Comment on lines +3 to +31
# Check for prerequisite before running the tests. If the prerequisites are not met, return $null to skip the tests.
# Following checks are performed to to current limitations of the Microsoft.Online.SharePoint.PowerShell module:
# - Run on Windows OS
# - Run in PowerShell 5 not 7
# - Check if the module is installed and loaded
# - Check if the user is connected to SharePoint Online with Connect-SpoService
if (-not ($PSVersionTable.OS -match "Windows" -or [System.Environment]::OSVersion.VersionString -match "Windows")) {
Write-Host "SharePoint Online tests can only be run on Windows OS. Skipping tests..." -ForegroundColor Yellow
return $null
}
if ($PSVersionTable.PSVersion.Major -ne 5) {
Write-Host "SharePoint Online tests can only be run in PowerShell 5. Skipping tests..." -ForegroundColor Yellow
return $null
}
if (-not (Get-Module -Name Microsoft.Online.SharePoint.PowerShell -ListAvailable)) {
Write-Host "Microsoft.Online.SharePoint.PowerShell module is not installed. Skipping tests..." -ForegroundColor Yellow
return $null
}
if (-not (Get-Module -Name Microsoft.Online.SharePoint.PowerShell)) {
Write-Host "Microsoft.Online.SharePoint.PowerShell module is not imported. Skipping tests..." -ForegroundColor Yellow
return $null
}
if (-not (Get-SpoTenant)) {
Write-Host "Not connected to SharePoint Online. Please connect using Connect-SpoService before running the tests. Skipping tests..." -ForegroundColor Yellow
return $null
}
}

Describe 'Maester/SpoTenant' -Tag 'Maester', 'SpoTenant' {
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prerequisite checks in BeforeDiscovery return $null, but the Describe block is still defined unconditionally. In this pattern, returning from BeforeDiscovery won’t actually skip the tests; it can still attempt to run and/or fail during discovery. Consider computing a $skip boolean + reason in BeforeDiscovery and applying -Skip:(...) (as done in other test files) to the Describe/It blocks instead of relying on return $null here.

Suggested change
# Check for prerequisite before running the tests. If the prerequisites are not met, return $null to skip the tests.
# Following checks are performed to to current limitations of the Microsoft.Online.SharePoint.PowerShell module:
# - Run on Windows OS
# - Run in PowerShell 5 not 7
# - Check if the module is installed and loaded
# - Check if the user is connected to SharePoint Online with Connect-SpoService
if (-not ($PSVersionTable.OS -match "Windows" -or [System.Environment]::OSVersion.VersionString -match "Windows")) {
Write-Host "SharePoint Online tests can only be run on Windows OS. Skipping tests..." -ForegroundColor Yellow
return $null
}
if ($PSVersionTable.PSVersion.Major -ne 5) {
Write-Host "SharePoint Online tests can only be run in PowerShell 5. Skipping tests..." -ForegroundColor Yellow
return $null
}
if (-not (Get-Module -Name Microsoft.Online.SharePoint.PowerShell -ListAvailable)) {
Write-Host "Microsoft.Online.SharePoint.PowerShell module is not installed. Skipping tests..." -ForegroundColor Yellow
return $null
}
if (-not (Get-Module -Name Microsoft.Online.SharePoint.PowerShell)) {
Write-Host "Microsoft.Online.SharePoint.PowerShell module is not imported. Skipping tests..." -ForegroundColor Yellow
return $null
}
if (-not (Get-SpoTenant)) {
Write-Host "Not connected to SharePoint Online. Please connect using Connect-SpoService before running the tests. Skipping tests..." -ForegroundColor Yellow
return $null
}
}
Describe 'Maester/SpoTenant' -Tag 'Maester', 'SpoTenant' {
# Check for prerequisites before running the tests. If the prerequisites are not met,
# mark the suite to be skipped during discovery.
# Following checks are performed due to current limitations of the Microsoft.Online.SharePoint.PowerShell module:
# - Run on Windows OS
# - Run in PowerShell 5 not 7
# - Check if the module is installed and loaded
# - Check if the user is connected to SharePoint Online with Connect-SpoService
$script:skipSpoTenantTests = $false
$script:skipSpoTenantTestsReason = $null
if (-not ($PSVersionTable.OS -match "Windows" -or [System.Environment]::OSVersion.VersionString -match "Windows")) {
$script:skipSpoTenantTests = $true
$script:skipSpoTenantTestsReason = "SharePoint Online tests can only be run on Windows OS. Skipping tests..."
}
elseif ($PSVersionTable.PSVersion.Major -ne 5) {
$script:skipSpoTenantTests = $true
$script:skipSpoTenantTestsReason = "SharePoint Online tests can only be run in PowerShell 5. Skipping tests..."
}
elseif (-not (Get-Module -Name Microsoft.Online.SharePoint.PowerShell -ListAvailable)) {
$script:skipSpoTenantTests = $true
$script:skipSpoTenantTestsReason = "Microsoft.Online.SharePoint.PowerShell module is not installed. Skipping tests..."
}
elseif (-not (Get-Module -Name Microsoft.Online.SharePoint.PowerShell)) {
$script:skipSpoTenantTests = $true
$script:skipSpoTenantTestsReason = "Microsoft.Online.SharePoint.PowerShell module is not imported. Skipping tests..."
}
elseif (-not (Get-SpoTenant)) {
$script:skipSpoTenantTests = $true
$script:skipSpoTenantTestsReason = "Not connected to SharePoint Online. Please connect using Connect-SpoService before running the tests. Skipping tests..."
}
if ($script:skipSpoTenantTests) {
Write-Host $script:skipSpoTenantTestsReason -ForegroundColor Yellow
}
}
Describe 'Maester/SpoTenant' -Tag 'Maester', 'SpoTenant' -Skip:($script:skipSpoTenantTests) {

Copilot uses AI. Check for mistakes.
Write-Host "Microsoft.Online.SharePoint.PowerShell module is not imported. Skipping tests..." -ForegroundColor Yellow
return $null
}
if (-not (Get-SpoTenant)) {
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (-not (Get-SpoTenant)) is used as a connection check during discovery, but Get-SPOTenant typically throws when not connected; this can break test discovery rather than skipping cleanly. Wrap this call in try/catch (with -ErrorAction Stop) and set the skip condition based on whether the call succeeds.

Suggested change
if (-not (Get-SpoTenant)) {
$isSpoConnected = $true
try {
Get-SPOTenant -ErrorAction Stop | Out-Null
}
catch {
$isSpoConnected = $false
}
if (-not $isSpoConnected) {

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +42
It 'MT.1114: Ensure Office 365 SharePoint infected files are disallowed for download' -Tag 'MT.1114', 'CIS', 'CIS M365v5', 'CIS 7.3.1', 'Severity:High' {
$result = Test-MtSpoPreventDownloadMaliciousFile
if ($null -ne $result) {
$result | Should -Be $true -Because 'Office 365 SharePoint infected files are disallowed for download.'
}
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is labeled/tagged as MT.1114 but the title/CIS mapping and the invoked function (Test-MtSpoPreventDownloadMaliciousFile) correspond to the infected-file-download control documented as MT.1119 / CIS 7.3.1. Please correct the ID/tag to MT.1119, and add a separate MT.1114 test once Test-MtSpoCustomScriptExecutionOnSiteCollection exists (it’s currently referenced in the manifest/config).

Copilot uses AI. Check for mistakes.
Comment thread powershell/Maester.psd1 Outdated
Comment thread powershell/public/maester/spo/Test-MtSpoGuestCannotShareUnownedItem.ps1 Outdated
Comment thread powershell/public/Connect-Maester.ps1 Outdated
@SamErde
Copy link
Copy Markdown
Contributor

SamErde commented May 5, 2026

@copilot resolve the merge conflicts in this pull request

SamErde and others added 5 commits May 5, 2026 06:51
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…dItem.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@SamErde
Copy link
Copy Markdown
Contributor

SamErde commented May 11, 2026

@copilot resolve the merge conflicts in this pull request

@Mynster9361
Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

@SamErde I think this PR can be closed taken over by this one:
#1755 in agreement with Henrik :)

@SamErde SamErde closed this May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request maester-test Related to a Maester test sharepoint Microsoft SharePoint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants