6 Commits

Author SHA1 Message Date
Doug Rios
4db0fd3742 Merge pull request #100 from CriticalSolutionsNetwork/Whatif-Bugfix
fix: whatif
2024-06-09 10:42:00 -05:00
DrIOS
83a8e31aa5 docs: Update CHANGELOG 2024-06-09 10:38:56 -05:00
DrIOS
b9de0638bb add: Output type to functions 2024-06-09 10:36:37 -05:00
DrIOS
5a0475c253 docs: update CHANGELOG.md 2024-06-09 09:50:55 -05:00
DrIOS
312aabc81c fix: whatif output and module install 2024-06-09 09:40:18 -05:00
DrIOS
e6da6d9d47 fix: whatif 2024-06-08 20:42:38 -05:00
23 changed files with 219 additions and 74 deletions

View File

@@ -6,6 +6,17 @@ The format is based on and uses the types of changes according to [Keep a Change
### Added ### Added
- Added output type to functions.
### Fixed
- Whatif support for `Invoke-M365SecurityAudit`.
- Whatif module output and module install process.
## [0.1.7] - 2024-06-08
### Added
- Added pipeline support to `Sync-CISExcelAndCsvData` function for `[CISAuditResult[]]` input. - Added pipeline support to `Sync-CISExcelAndCsvData` function for `[CISAuditResult[]]` input.
### Changed ### Changed
@@ -16,6 +27,12 @@ The format is based on and uses the types of changes according to [Keep a Change
- Enhanced `Invoke-M365SecurityAudit` to allow flexible inclusion and exclusion of specific recommendations, IG filters, and profile levels. - 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. - SupportsShoudProcess to also bypass connection checks in `Invoke-M365SecurityAudit` as well as Disconnect-M365Suite.
## [0.1.6] - 2024-06-08
### Added
- Added pipeline support to `Sync-CISExcelAndCsvData` function for `[CISAuditResult[]]` input.
## [0.1.5] - 2024-06-08 ## [0.1.5] - 2024-06-08
### Added ### Added

View File

@@ -4,7 +4,7 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
<# <#
$ver = "v0.1.6" $ver = "v0.1.7"
git checkout main git checkout main
git pull origin main git pull origin main
git tag -a $ver -m "Release version $ver refactor Update" git tag -a $ver -m "Release version $ver refactor Update"

View File

@@ -1,33 +1,37 @@
function Assert-ModuleAvailability { function Assert-ModuleAvailability {
[OutputType([void]) ]
param( param(
[string]$ModuleName, [string]$ModuleName,
[string]$RequiredVersion, [string]$RequiredVersion,
[string]$SubModuleName [string[]]$SubModules = @()
) )
try { try {
$module = Get-Module -ListAvailable -Name $ModuleName | Where-Object { $_.Version -ge [version]$RequiredVersion } $module = Get-Module -ListAvailable -Name $ModuleName | Where-Object { $_.Version -ge [version]$RequiredVersion }
if ($null -eq $module) {$auditResult.Profile if ($null -eq $module) {
Write-Host "Installing $ModuleName module..." Write-Information "Installing $ModuleName module..." -InformationAction Continue
Install-Module -Name $ModuleName -RequiredVersion $RequiredVersion -Force -AllowClobber -Scope CurrentUser | Out-Null Install-Module -Name $ModuleName -RequiredVersion $RequiredVersion -Force -AllowClobber -Scope CurrentUser | Out-Null
} }
elseif ($module.Version -lt [version]$RequiredVersion) { elseif ($module.Version -lt [version]$RequiredVersion) {
Write-Host "Updating $ModuleName module to required version..." Write-Information "Updating $ModuleName module to required version..." -InformationAction Continue
Update-Module -Name $ModuleName -RequiredVersion $RequiredVersion -Force | Out-Null Update-Module -Name $ModuleName -RequiredVersion $RequiredVersion -Force | Out-Null
} }
else { else {
Write-Host "$ModuleName module is already at required version or newer." Write-Information "$ModuleName module is already at required version or newer." -InformationAction Continue
} }
if ($SubModuleName) { if ($SubModules.Count -gt 0) {
Import-Module -Name "$ModuleName.$SubModuleName" -RequiredVersion $RequiredVersion -ErrorAction Stop | Out-Null foreach ($subModule in $SubModules) {
} Write-Information "Importing submodule $ModuleName.$subModule..." -InformationAction Continue
else { Import-Module -Name "$ModuleName.$subModule" -RequiredVersion $RequiredVersion -ErrorAction Stop | Out-Null
}
} else {
Write-Information "Importing module $ModuleName..." -InformationAction Continue
Import-Module -Name $ModuleName -RequiredVersion $RequiredVersion -ErrorAction Stop | Out-Null Import-Module -Name $ModuleName -RequiredVersion $RequiredVersion -ErrorAction Stop | Out-Null
} }
} }
catch { catch {
Write-Warning "An error occurred with module $ModuleName`: $_" Write-Warning "An error occurred with module $ModuleName`: $_"
} }
} }

View File

@@ -1,4 +1,5 @@
function Connect-M365Suite { function Connect-M365Suite {
[OutputType([void])]
[CmdletBinding()] [CmdletBinding()]
param ( param (
[Parameter(Mandatory=$false)] [Parameter(Mandatory=$false)]

View File

@@ -1,4 +1,5 @@
function Disconnect-M365Suite { function Disconnect-M365Suite {
[OutputType([void])]
param ( param (
[Parameter(Mandatory)] [Parameter(Mandatory)]
[string[]]$RequiredConnections [string[]]$RequiredConnections

View File

@@ -1,5 +1,9 @@
function Format-MissingAction { function Format-MissingAction {
param ([array]$missingActions) [CmdletBinding()]
[OutputType([hashtable])]
param (
[array]$missingActions
)
$actionGroups = @{ $actionGroups = @{
"Admin" = @() "Admin" = @()
@@ -22,4 +26,4 @@ function Format-MissingAction {
} }
return $formattedResults return $formattedResults
} }

View File

@@ -0,0 +1,19 @@
function Format-RequiredModuleList {
[CmdletBinding()]
[OutputType([string])]
param (
[Parameter(Mandatory = $true)]
[System.Object[]]$RequiredModules
)
$requiredModulesFormatted = ""
foreach ($module in $RequiredModules) {
if ($module.SubModules -and $module.SubModules.Count -gt 0) {
$subModulesFormatted = $module.SubModules -join ', '
$requiredModulesFormatted += "$($module.ModuleName) (SubModules: $subModulesFormatted), "
} else {
$requiredModulesFormatted += "$($module.ModuleName), "
}
}
return $requiredModulesFormatted.TrimEnd(", ")
}

View File

@@ -1,4 +1,6 @@
function Get-MostCommonWord { function Get-MostCommonWord {
[CmdletBinding()]
[OutputType([string])]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string[]]$InputStrings [string[]]$InputStrings
@@ -19,4 +21,4 @@ function Get-MostCommonWord {
} else { } else {
return $null return $null
} }
} }

View File

@@ -12,22 +12,16 @@ function Get-RequiredModule {
switch ($PSCmdlet.ParameterSetName) { switch ($PSCmdlet.ParameterSetName) {
'AuditFunction' { 'AuditFunction' {
return @( return @(
@{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0" }, @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0"; SubModules = @() },
@{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182" }, @{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182"; SubModules = @() },
@{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Authentication" }, @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModules = @("Groups", "DeviceManagement", "Users", "Identity.DirectoryManagement", "Identity.SignIns") },
@{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Users" }, @{ ModuleName = "Microsoft.Online.SharePoint.PowerShell"; RequiredVersion = "16.0.24009.12000"; SubModules = @() },
@{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Groups" }, @{ ModuleName = "MicrosoftTeams"; RequiredVersion = "5.5.0"; SubModules = @() }
@{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "DirectoryObjects" },
@{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Domains" },
@{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Reports" },
@{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Mail" },
@{ ModuleName = "Microsoft.Online.SharePoint.PowerShell"; RequiredVersion = "16.0.24009.12000" },
@{ ModuleName = "MicrosoftTeams"; RequiredVersion = "5.5.0" }
) )
} }
'SyncFunction' { 'SyncFunction' {
return @( return @(
@{ ModuleName = "ImportExcel"; RequiredVersion = "7.8.9" } @{ ModuleName = "ImportExcel"; RequiredVersion = "7.8.9"; SubModules = @() }
) )
} }
default { default {

View File

@@ -1,4 +1,6 @@
function Get-TestDefinitionsObject { function Get-TestDefinitionsObject {
[CmdletBinding()]
[OutputType([object[]])]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[object[]]$TestDefinitions, [object[]]$TestDefinitions,
@@ -60,4 +62,4 @@ function Get-TestDefinitionsObject {
Write-Verbose "Filtered test definitions count: $($TestDefinitions.Count)" Write-Verbose "Filtered test definitions count: $($TestDefinitions.Count)"
return $TestDefinitions return $TestDefinitions
} }

View File

@@ -0,0 +1,28 @@
function Get-UniqueConnection {
[CmdletBinding()]
[OutputType([string[]])]
param (
[Parameter(Mandatory = $true)]
[string[]]$Connections
)
$uniqueConnections = @()
if ($Connections -contains "AzureAD" -or $Connections -contains "AzureAD | EXO" -or $Connections -contains "AzureAD | EXO | Microsoft Graph") {
$uniqueConnections += "AzureAD"
}
if ($Connections -contains "Microsoft Graph" -or $Connections -contains "AzureAD | EXO | Microsoft Graph") {
$uniqueConnections += "Microsoft Graph"
}
if ($Connections -contains "EXO" -or $Connections -contains "AzureAD | EXO" -or $Connections -contains "Microsoft Teams | EXO" -or $Connections -contains "AzureAD | EXO | Microsoft Graph") {
$uniqueConnections += "EXO"
}
if ($Connections -contains "SPO") {
$uniqueConnections += "SPO"
}
if ($Connections -contains "Microsoft Teams" -or $Connections -contains "Microsoft Teams | EXO") {
$uniqueConnections += "Microsoft Teams"
}
return $uniqueConnections | Sort-Object -Unique
}

View File

@@ -1,5 +1,6 @@
function Initialize-CISAuditResult { function Initialize-CISAuditResult {
[CmdletBinding()] [CmdletBinding()]
[OutputType([CISAuditResult])]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$Rec, [string]$Rec,

View File

@@ -1,4 +1,5 @@
function Invoke-TestFunction { function Invoke-TestFunction {
[OutputType([CISAuditResult[]])]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[PSObject]$FunctionFile, [PSObject]$FunctionFile,

View File

@@ -1,4 +1,5 @@
function Measure-AuditResult { function Measure-AuditResult {
[OutputType([void])]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[System.Collections.ArrayList]$AllAuditResults, [System.Collections.ArrayList]$AllAuditResults,

View File

@@ -1,5 +1,6 @@
function Merge-CISExcelAndCsvData { function Merge-CISExcelAndCsvData {
[CmdletBinding(DefaultParameterSetName = 'CsvInput')] [CmdletBinding(DefaultParameterSetName = 'CsvInput')]
[OutputType([PSCustomObject[]])]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$ExcelPath, [string]$ExcelPath,

View File

@@ -1,4 +1,6 @@
function New-MergedObject { function New-MergedObject {
[CmdletBinding()]
[OutputType([PSCustomObject])]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[psobject]$ExcelItem, [psobject]$ExcelItem,

View File

@@ -1,4 +1,5 @@
function Update-CISExcelWorksheet { function Update-CISExcelWorksheet {
[OutputType([void])]
[CmdletBinding()] [CmdletBinding()]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]

View File

@@ -1,28 +1,29 @@
function Update-WorksheetCell { function Update-WorksheetCell {
param ( [OutputType([void])]
$Worksheet, param (
$Data, $Worksheet,
$StartingRowIndex $Data,
) $StartingRowIndex
)
# Check and set headers # Check and set headers
$firstItem = $Data[0] $firstItem = $Data[0]
$colIndex = 1 $colIndex = 1
foreach ($property in $firstItem.PSObject.Properties) { foreach ($property in $firstItem.PSObject.Properties) {
if ($StartingRowIndex -eq 2 -and $Worksheet.Cells[1, $colIndex].Value -eq $null) { if ($StartingRowIndex -eq 2 -and $Worksheet.Cells[1, $colIndex].Value -eq $null) {
$Worksheet.Cells[1, $colIndex].Value = $property.Name $Worksheet.Cells[1, $colIndex].Value = $property.Name
}
$colIndex++
}
# Iterate over each row in the data and update cells
$rowIndex = $StartingRowIndex
foreach ($item in $Data) {
$colIndex = 1
foreach ($property in $item.PSObject.Properties) {
$Worksheet.Cells[$rowIndex, $colIndex].Value = $property.Value
$colIndex++
}
$rowIndex++
}
} }
$colIndex++
}
# Iterate over each row in the data and update cells
$rowIndex = $StartingRowIndex
foreach ($item in $Data) {
$colIndex = 1
foreach ($property in $item.PSObject.Properties) {
$Worksheet.Cells[$rowIndex, $colIndex].Value = $property.Value
$colIndex++
}
$rowIndex++
}
}

View File

@@ -114,7 +114,6 @@
.LINK .LINK
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit
#> #>
function Invoke-M365SecurityAudit { function Invoke-M365SecurityAudit {
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')] [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')]
[OutputType([CISAuditResult[]])] [OutputType([CISAuditResult[]])]
@@ -150,12 +149,12 @@ function Invoke-M365SecurityAudit {
[Parameter(Mandatory = $true, ParameterSetName = 'RecFilter')] [Parameter(Mandatory = $true, ParameterSetName = 'RecFilter')]
[ValidateSet( [ValidateSet(
'1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', ` '1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
'2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', ` '2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', `
'5.1.8.1', '6.1.1', '6.1.2', '6.1.3', '6.2.1', '6.2.2', '6.2.3', '6.3.1', ` '5.1.8.1', '6.1.1', '6.1.2', '6.1.3', '6.2.1', '6.2.2', '6.2.3', '6.3.1', `
'6.5.1', '6.5.2', '6.5.3', '7.2.1', '7.2.10', '7.2.2', '7.2.3', '7.2.4', ` '6.5.1', '6.5.2', '6.5.3', '7.2.1', '7.2.10', '7.2.2', '7.2.3', '7.2.4', `
'7.2.5', '7.2.6', '7.2.7', '7.2.9', '7.3.1', '7.3.2', '7.3.4', '8.1.1', ` '7.2.5', '7.2.6', '7.2.7', '7.2.9', '7.3.1', '7.3.2', '7.3.4', '8.1.1', `
'8.1.2', '8.2.1', '8.5.1', '8.5.2', '8.5.3', '8.5.4', '8.5.5', '8.5.6', ` '8.1.2', '8.2.1', '8.5.1', '8.5.2', '8.5.3', '8.5.4', '8.5.5', '8.5.6', `
'8.5.7', '8.6.1' '8.5.7', '8.6.1'
)] )]
[string[]]$IncludeRecommendation, [string[]]$IncludeRecommendation,
@@ -163,12 +162,12 @@ function Invoke-M365SecurityAudit {
[Parameter(Mandatory = $true, ParameterSetName = 'SkipRecFilter')] [Parameter(Mandatory = $true, ParameterSetName = 'SkipRecFilter')]
[ValidateSet( [ValidateSet(
'1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', ` '1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
'2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', ` '2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', `
'5.1.8.1', '6.1.1', '6.1.2', '6.1.3', '6.2.1', '6.2.2', '6.2.3', '6.3.1', ` '5.1.8.1', '6.1.1', '6.1.2', '6.1.3', '6.2.1', '6.2.2', '6.2.3', '6.3.1', `
'6.5.1', '6.5.2', '6.5.3', '7.2.1', '7.2.10', '7.2.2', '7.2.3', '7.2.4', ` '6.5.1', '6.5.2', '6.5.3', '7.2.1', '7.2.10', '7.2.2', '7.2.3', '7.2.4', `
'7.2.5', '7.2.6', '7.2.7', '7.2.9', '7.3.1', '7.3.2', '7.3.4', '8.1.1', ` '7.2.5', '7.2.6', '7.2.7', '7.2.9', '7.3.1', '7.3.2', '7.3.4', '8.1.1', `
'8.1.2', '8.2.1', '8.5.1', '8.5.2', '8.5.3', '8.5.4', '8.5.5', '8.5.6', ` '8.1.2', '8.2.1', '8.5.1', '8.5.2', '8.5.3', '8.5.4', '8.5.5', '8.5.6', `
'8.5.7', '8.6.1' '8.5.7', '8.6.1'
)] )]
[string[]]$SkipRecommendation, [string[]]$SkipRecommendation,
@@ -183,12 +182,18 @@ function Invoke-M365SecurityAudit {
$script:MaximumFunctionCount = 8192 $script:MaximumFunctionCount = 8192
} }
# Ensure required modules are installed # Ensure required modules are installed
if (!($NoModuleCheck) -and $PSCmdlet.ShouldProcess("Check for required modules", "Check")) { $requiredModules = Get-RequiredModule -AuditFunction
$requiredModules = Get-RequiredModule -AuditFunction
# Format the required modules list
$requiredModulesFormatted = Format-RequiredModuleList -RequiredModules $requiredModules
# Check and install required modules if necessary
if (!($NoModuleCheck) -and $PSCmdlet.ShouldProcess("Check for required modules: $requiredModulesFormatted", "Check")) {
foreach ($module in $requiredModules) { foreach ($module in $requiredModules) {
Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModules $module.SubModules
} }
} }
# Load test definitions from CSV # Load test definitions from CSV
$testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath "helper\TestDefinitions.csv" $testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath "helper\TestDefinitions.csv"
$testDefinitions = Import-Csv -Path $testDefinitionsPath $testDefinitions = Import-Csv -Path $testDefinitionsPath
@@ -207,7 +212,7 @@ function Invoke-M365SecurityAudit {
$testDefinitions = Get-TestDefinitionsObject @params $testDefinitions = Get-TestDefinitionsObject @params
# Extract unique connections needed # Extract unique connections needed
$requiredConnections = $testDefinitions.Connection | Sort-Object -Unique $requiredConnections = $testDefinitions.Connection | Sort-Object -Unique
if ($requiredConnections -contains 'SPO'){ if ($requiredConnections -contains 'SPO') {
if (-not $TenantAdminUrl) { if (-not $TenantAdminUrl) {
$requiredConnections = $requiredConnections | Where-Object { $_ -ne 'SPO' } $requiredConnections = $requiredConnections | Where-Object { $_ -ne 'SPO' }
$testDefinitions = $testDefinitions | Where-Object { $_.Connection -ne 'SPO' } $testDefinitions = $testDefinitions | Where-Object { $_.Connection -ne 'SPO' }
@@ -235,10 +240,14 @@ function Invoke-M365SecurityAudit {
$currentTestIndex = 0 $currentTestIndex = 0
# Establishing connections if required # Establishing connections if required
if (!($DoNotConnect) -and $PSCmdlet.ShouldProcess("Establish connections to Microsoft 365 services", "Connect")) { $actualUniqueConnections = Get-UniqueConnection -Connections $requiredConnections
if (!($DoNotConnect) -and $PSCmdlet.ShouldProcess("Establish connections to Microsoft 365 services: $($actualUniqueConnections -join ', ')", "Connect")) {
Write-Information "Establishing connections to Microsoft 365 services: $($actualUniqueConnections -join ', ')" -InformationAction Continue
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections
} }
Write-Information "A total of $($totalTests) tests were selected to run..." -InformationAction Continue
# Import the test functions # Import the test functions
$testFiles | ForEach-Object { $testFiles | ForEach-Object {
$currentTestIndex++ $currentTestIndex++
@@ -269,11 +278,11 @@ function Invoke-M365SecurityAudit {
} }
End { End {
if (!($DoNotDisconnect) -and $PSCmdlet.ShouldProcess("Disconnect from Microsoft 365 services", "Disconnect")) { if (!($DoNotDisconnect) -and $PSCmdlet.ShouldProcess("Disconnect from Microsoft 365 services: $($actualUniqueConnections -join ', ')", "Disconnect")) {
# Clean up sessions # Clean up sessions
Disconnect-M365Suite -RequiredConnections $requiredConnections Disconnect-M365Suite -RequiredConnections $requiredConnections
} }
if ($PSCmdlet.ShouldProcess("Measure and display audit results", "Measure")) { if ($PSCmdlet.ShouldProcess("Measure and display audit results for $($totalTests) tests", "Measure")) {
# Call the private function to calculate and display results # Call the private function to calculate and display results
Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests
# Return all collected audit results # Return all collected audit results
@@ -281,3 +290,4 @@ function Invoke-M365SecurityAudit {
} }
} }
} }

View File

@@ -44,6 +44,7 @@ If the SkipUpdate switch is used, the function returns an array of custom object
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Sync-CISExcelAndCsvData https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Sync-CISExcelAndCsvData
#> #>
function Sync-CISExcelAndCsvData { function Sync-CISExcelAndCsvData {
[OutputType([void], [PSCustomObject[]])]
[CmdletBinding(DefaultParameterSetName = 'CsvInput')] [CmdletBinding(DefaultParameterSetName = 'CsvInput')]
param ( param (
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]

View File

@@ -42,7 +42,7 @@ function Test-PasswordNeverExpirePolicy {
$failureReasons = if ($isCompliant) { $failureReasons = if ($isCompliant) {
"N/A" "N/A"
} else { } else {
"Password expiration is not set to never expire for domain $domainName. Run the following command to remediate: `nUpdate-MgDomain -DomainId $domainName -PasswordValidityPeriodInDays 2147483647 -PasswordNotificationWindowInDays 30" "Password expiration is not set to never expire for domain $domainName. Run the following command to remediate: `nUpdate-MgDomain -DomainId $domainName -PasswordValidityPeriodInDays 2147483647 -PasswordNotificationWindowInDays 30`n"
} }
$details = "$domainName|$passwordPolicy days|$isDefault" $details = "$domainName|$passwordPolicy days|$isDefault"

View File

@@ -0,0 +1,27 @@
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
}).BaseName
Import-Module $ProjectName
InModuleScope $ProjectName {
Describe Get-PrivateFunction {
Context 'Default' {
BeforeEach {
$return = Get-PrivateFunction -PrivateData 'string'
}
It 'Returns a single object' {
($return | Measure-Object).Count | Should -Be 1
}
It 'Returns a string based on the parameter PrivateData' {
$return | Should -Be 'string'
}
}
}
}

View File

@@ -0,0 +1,27 @@
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
}).BaseName
Import-Module $ProjectName
InModuleScope $ProjectName {
Describe Get-PrivateFunction {
Context 'Default' {
BeforeEach {
$return = Get-PrivateFunction -PrivateData 'string'
}
It 'Returns a single object' {
($return | Measure-Object).Count | Should -Be 1
}
It 'Returns a string based on the parameter PrivateData' {
$return | Should -Be 'string'
}
}
}
}