Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
014c42b3fe | ||
|
fbfb5b5986 | ||
|
03b5bb47e2 | ||
|
9dc99636d3 | ||
|
afe657ffc0 | ||
|
702f557579 | ||
|
f855ef7d0b | ||
|
270e980a57 | ||
|
ff90669984 | ||
|
f2e799af2f | ||
|
4a4d200197 | ||
|
9199d97fc2 | ||
|
5d681f3d72 | ||
|
f926c63533 |
@@ -8,6 +8,14 @@ The format is based on and uses the types of changes according to [Keep a Change
|
||||
|
||||
- Added pipeline support to `Sync-CISExcelAndCsvData` function for `[CISAuditResult[]]` input.
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `Connect-M365Suite` to make `TenantAdminUrl` an optional parameter.
|
||||
- Updated `Invoke-M365SecurityAudit` to make `TenantAdminUrl` an optional parameter.
|
||||
- Improved connection handling and error messaging in `Connect-M365Suite`.
|
||||
- Enhanced `Invoke-M365SecurityAudit` to allow flexible inclusion and exclusion of specific recommendations, IG filters, and profile levels.
|
||||
- SupportsShoudProcess to also bypass connection checks in `Invoke-M365SecurityAudit` as well as Disconnect-M365Suite.
|
||||
|
||||
## [0.1.5] - 2024-06-08
|
||||
|
||||
### Added
|
||||
|
BIN
docs/index.html
BIN
docs/index.html
Binary file not shown.
@@ -14,4 +14,72 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
|
||||
# git tag -d $ver
|
||||
#>
|
||||
|
||||
# Refresh authentication to ensure the correct scopes
|
||||
gh auth refresh -s project,read:project,write:project,repo
|
||||
|
||||
# Create the project
|
||||
gh project create --owner CriticalSolutionsNetwork --title "Test Validation Project"
|
||||
|
||||
$repoOwner = "CriticalSolutionsNetwork"
|
||||
$repoName = "M365FoundationsCISReport"
|
||||
$directoryPath = ".\source\tests"
|
||||
$projectName = "Test Validation Project"
|
||||
|
||||
# Function to create GitHub issues
|
||||
function Create-GitHubIssue {
|
||||
param (
|
||||
[string]$title,
|
||||
[string]$body,
|
||||
[string]$project
|
||||
)
|
||||
|
||||
# Create the issue and add it to the specified project
|
||||
$issue = gh issue create --repo "$repoOwner/$repoName" --title "$title" --body "$body" --project "$project"
|
||||
return $issue
|
||||
}
|
||||
|
||||
# Load test definitions from CSV
|
||||
$testDefinitionsPath = ".\source\helper\TestDefinitions.csv"
|
||||
$testDefinitions = Import-Csv -Path $testDefinitionsPath
|
||||
|
||||
# Iterate over each .ps1 file in the directory
|
||||
Get-ChildItem -Path $directoryPath -Filter "*.ps1" | ForEach-Object {
|
||||
$fileName = $_.Name
|
||||
$testDefinition = $testDefinitions | Where-Object { $_.TestFileName -eq $fileName }
|
||||
|
||||
if ($testDefinition) {
|
||||
$rec = $testDefinition.Rec
|
||||
$elevel = $testDefinition.ELevel
|
||||
$profileLevel = $testDefinition.ProfileLevel
|
||||
$ig1 = $testDefinition.IG1
|
||||
$ig2 = $testDefinition.IG2
|
||||
$ig3 = $testDefinition.IG3
|
||||
$connection = $testDefinition.Connection
|
||||
|
||||
$issueTitle = "Rec: $rec - Validate $fileName, ELevel: $elevel, ProfileLevel: $profileLevel, IG1: $ig1, IG2: $ig2, IG3: $ig3, Connection: $connection"
|
||||
$issueBody = @"
|
||||
# Validation for $fileName
|
||||
|
||||
## Tasks
|
||||
- [ ] Validate test for a pass
|
||||
- Description of passing criteria:
|
||||
- [ ] Validate test for a fail
|
||||
- Description of failing criteria:
|
||||
- [ ] Add notes and observations
|
||||
- Placeholder for additional notes:
|
||||
"@
|
||||
|
||||
# Create the issue using GitHub CLI
|
||||
try {
|
||||
Create-GitHubIssue -title "$issueTitle" -body "$issueBody" -project "$projectName"
|
||||
Write-Output "Created issue for $fileName"
|
||||
} catch {
|
||||
Write-Error "Failed to create issue for $fileName : $_"
|
||||
}
|
||||
|
||||
# Introduce a delay of 2 seconds
|
||||
Start-Sleep -Seconds 2
|
||||
} else {
|
||||
Write-Warning "No matching test definition found for $fileName"
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
function Connect-M365Suite {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$TenantAdminUrl,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
|
@@ -4,7 +4,7 @@
|
||||
.DESCRIPTION
|
||||
The Invoke-M365SecurityAudit cmdlet performs a comprehensive security audit based on the specified parameters. It allows auditing of various configurations and settings within a Microsoft 365 environment, such as compliance with CIS benchmarks.
|
||||
.PARAMETER TenantAdminUrl
|
||||
The URL of the tenant admin. This parameter is mandatory.
|
||||
The URL of the tenant admin. If not specified, none of the SharePoint Online tests will run.
|
||||
.PARAMETER M365DomainForPWPolicyTest
|
||||
The domain name of the Microsoft 365 environment to test. This parameter is not mandatory and by default it will pass/fail all found domains as a group if a specific domain is not specified.
|
||||
.PARAMETER ELevel
|
||||
@@ -28,22 +28,77 @@
|
||||
.PARAMETER NoModuleCheck
|
||||
If specified, the cmdlet will not check for the presence of required modules.
|
||||
.EXAMPLE
|
||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -ELevel "E5" -ProfileLevel "L1"
|
||||
|
||||
PS> Invoke-M365SecurityAudit
|
||||
Performs a security audit using default parameters.
|
||||
Output:
|
||||
Status : Fail
|
||||
ELevel : E3
|
||||
ProfileLevel: L1
|
||||
Connection : Microsoft Graph
|
||||
Rec : 1.1.1
|
||||
Result : False
|
||||
Details : Non-compliant accounts:
|
||||
Username | Roles | HybridStatus | Missing Licence
|
||||
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||
FailureReason: Non-Compliant Accounts: 2
|
||||
.EXAMPLE
|
||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com" -ELevel "E5" -ProfileLevel "L1"
|
||||
Performs a security audit for the E5 level and L1 profile in the specified Microsoft 365 environment.
|
||||
Output:
|
||||
Status : Fail
|
||||
ELevel : E5
|
||||
ProfileLevel: L1
|
||||
Connection : Microsoft Graph
|
||||
Rec : 1.1.1
|
||||
Result : False
|
||||
Details : Non-compliant accounts:
|
||||
Username | Roles | HybridStatus | Missing Licence
|
||||
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||
FailureReason: Non-Compliant Accounts: 2
|
||||
.EXAMPLE
|
||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -IncludeIG1
|
||||
|
||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com" -IncludeIG1
|
||||
Performs an audit including all tests where IG1 is true.
|
||||
Output:
|
||||
Status : Fail
|
||||
ELevel : E3
|
||||
ProfileLevel: L1
|
||||
Connection : Microsoft Graph
|
||||
Rec : 1.1.1
|
||||
Result : False
|
||||
Details : Non-compliant accounts:
|
||||
Username | Roles | HybridStatus | Missing Licence
|
||||
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||
FailureReason: Non-Compliant Accounts: 2
|
||||
.EXAMPLE
|
||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -SkipRecommendation '1.1.3', '2.1.1'
|
||||
|
||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com" -SkipRecommendation '1.1.3', '2.1.1'
|
||||
Performs an audit while excluding specific recommendations 1.1.3 and 2.1.1.
|
||||
Output:
|
||||
Status : Fail
|
||||
ELevel : E3
|
||||
ProfileLevel: L1
|
||||
Connection : Microsoft Graph
|
||||
Rec : 1.1.1
|
||||
Result : False
|
||||
Details : Non-compliant accounts:
|
||||
Username | Roles | HybridStatus | Missing Licence
|
||||
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||
FailureReason: Non-Compliant Accounts: 2
|
||||
.EXAMPLE
|
||||
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com"
|
||||
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com"
|
||||
PS> $auditResults | Export-Csv -Path "auditResults.csv" -NoTypeInformation
|
||||
|
||||
Captures the audit results into a variable and exports them to a CSV file.
|
||||
Output:
|
||||
CISAuditResult[]
|
||||
auditResults.csv
|
||||
.EXAMPLE
|
||||
PS> Invoke-M365SecurityAudit -WhatIf
|
||||
Displays what would happen if the cmdlet is run without actually performing the audit.
|
||||
Output:
|
||||
What if: Performing the operation "Invoke-M365SecurityAudit" on target "Microsoft 365 environment".
|
||||
.INPUTS
|
||||
None. You cannot pipe objects to Invoke-M365SecurityAudit.
|
||||
.OUTPUTS
|
||||
@@ -59,11 +114,12 @@
|
||||
.LINK
|
||||
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit
|
||||
#>
|
||||
|
||||
function Invoke-M365SecurityAudit {
|
||||
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')]
|
||||
[OutputType([CISAuditResult[]])]
|
||||
param (
|
||||
[Parameter(Mandatory = $true, HelpMessage = "The SharePoint tenant admin URL, which should end with '-admin.sharepoint.com'.")]
|
||||
[Parameter(Mandatory = $false, HelpMessage = "The SharePoint tenant admin URL, which should end with '-admin.sharepoint.com'. If not specified none of the Sharepoint Online tests will run.")]
|
||||
[ValidatePattern('^https://[a-zA-Z0-9-]+-admin\.sharepoint\.com$')]
|
||||
[string]$TenantAdminUrl,
|
||||
|
||||
@@ -127,7 +183,7 @@ function Invoke-M365SecurityAudit {
|
||||
$script:MaximumFunctionCount = 8192
|
||||
}
|
||||
# Ensure required modules are installed
|
||||
if (!($NoModuleCheck)) {
|
||||
if (!($NoModuleCheck) -and $PSCmdlet.ShouldProcess("Check for required modules", "Check")) {
|
||||
$requiredModules = Get-RequiredModule -AuditFunction
|
||||
foreach ($module in $requiredModules) {
|
||||
Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName
|
||||
@@ -151,9 +207,14 @@ function Invoke-M365SecurityAudit {
|
||||
$testDefinitions = Get-TestDefinitionsObject @params
|
||||
# Extract unique connections needed
|
||||
$requiredConnections = $testDefinitions.Connection | Sort-Object -Unique
|
||||
# Establishing connections if required
|
||||
if (!($DoNotConnect)) {
|
||||
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections
|
||||
if ($requiredConnections -contains 'SPO'){
|
||||
if (-not $TenantAdminUrl) {
|
||||
$requiredConnections = $requiredConnections | Where-Object { $_ -ne 'SPO' }
|
||||
$testDefinitions = $testDefinitions | Where-Object { $_.Connection -ne 'SPO' }
|
||||
if ($null -eq $testDefinitions) {
|
||||
throw "No tests to run as no SharePoint Online tests are available."
|
||||
}
|
||||
}
|
||||
}
|
||||
# Determine which test files to load based on filtering
|
||||
$testsToLoad = $testDefinitions.TestFileName | ForEach-Object { $_ -replace '.ps1$', '' }
|
||||
@@ -162,6 +223,7 @@ function Invoke-M365SecurityAudit {
|
||||
# Initialize a collection to hold failed test details
|
||||
$script:FailedTests = [System.Collections.ArrayList]::new()
|
||||
} # End Begin
|
||||
|
||||
Process {
|
||||
$allAuditResults = [System.Collections.ArrayList]::new() # Initialize a collection to hold all results
|
||||
# Dynamically dot-source the test scripts
|
||||
@@ -172,6 +234,11 @@ function Invoke-M365SecurityAudit {
|
||||
$totalTests = $testFiles.Count
|
||||
$currentTestIndex = 0
|
||||
|
||||
# Establishing connections if required
|
||||
if (!($DoNotConnect) -and $PSCmdlet.ShouldProcess("Establish connections to Microsoft 365 services", "Connect")) {
|
||||
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections
|
||||
}
|
||||
|
||||
# Import the test functions
|
||||
$testFiles | ForEach-Object {
|
||||
$currentTestIndex++
|
||||
@@ -202,14 +269,15 @@ function Invoke-M365SecurityAudit {
|
||||
}
|
||||
|
||||
End {
|
||||
if (!($DoNotDisconnect)) {
|
||||
if (!($DoNotDisconnect) -and $PSCmdlet.ShouldProcess("Disconnect from Microsoft 365 services", "Disconnect")) {
|
||||
# Clean up sessions
|
||||
Disconnect-M365Suite -RequiredConnections $requiredConnections
|
||||
}
|
||||
if ($PSCmdlet.ShouldProcess("Measure and display audit results", "Measure")) {
|
||||
# Call the private function to calculate and display results
|
||||
Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests
|
||||
# Return all collected audit results
|
||||
return $allAuditResults.ToArray() | Sort-Object -Property Rec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user