diff --git a/CHANGELOG.md b/CHANGELOG.md index 60c65fa..18e8a5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,9 @@ The format is based on and uses the types of changes according to [Keep a Change - Improved `Test-RestrictCustomScripts` to handle long URL lengths better by extracting and replacing common hostnames, and provided detailed output. - Added sorting to output. - Created new functions for improved modularity. -- Parameter validation for excel and csv path in sync function +- Parameter validation for Excel and CSV path in sync function. - Added Output type to tests. +- Added `M365DomainForPWPolicyTest` parameter to `Invoke-M365SecurityAudit` to specify testing only the default domain for password expiration policy when '1.3.1' is included in the tests. ### Fixed @@ -34,6 +35,7 @@ The format is based on and uses the types of changes according to [Keep a Change - Fixed the issue with the output in `Test-RestrictCustomScripts` to ensure no extra spaces between table headers and data. + ## [0.1.4] - 2024-05-30 ### Added diff --git a/README.md b/README.md index c7d73b9..c33fe48 100644 Binary files a/README.md and b/README.md differ diff --git a/docs/index.html b/docs/index.html index 0d68372..81728b4 100644 Binary files a/docs/index.html and b/docs/index.html differ diff --git a/source/Private/Invoke-TestFunction.ps1 b/source/Private/Invoke-TestFunction.ps1 index d9a5997..5f6b944 100644 --- a/source/Private/Invoke-TestFunction.ps1 +++ b/source/Private/Invoke-TestFunction.ps1 @@ -3,7 +3,7 @@ function Invoke-TestFunction { [Parameter(Mandatory = $true)] [PSObject]$FunctionFile, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [string]$DomainName ) diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index aa22711..87509c6 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -5,8 +5,8 @@ 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. - .PARAMETER DomainName - The domain name of the Microsoft 365 environment. This parameter is mandatory. + .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 Specifies the E-Level (E3 or E5) for the audit. This parameter is optional and can be combined with the ProfileLevel parameter. .PARAMETER ProfileLevel @@ -67,9 +67,9 @@ function Invoke-M365SecurityAudit { [ValidatePattern('^https://[a-zA-Z0-9-]+-admin\.sharepoint\.com$')] [string]$TenantAdminUrl, - [Parameter(Mandatory = $true, HelpMessage = "The domain name of your organization, e.g., 'example.com'.")] + [Parameter(Mandatory = $false, HelpMessage = "Specify this to test only the default domain for password expiration policy when '1.3.1' is included in the tests to be run. The domain name of your organization, e.g., 'example.com'.")] [ValidatePattern('^[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$')] - [string]$DomainName, + [string]$M365DomainForPWPolicyTest, # E-Level with optional ProfileLevel selection [Parameter(Mandatory = $true, ParameterSetName = 'ELevelFilter')] @@ -194,7 +194,7 @@ function Invoke-M365SecurityAudit { Write-Progress -Activity "Executing Tests" -Status "Executing $($currentTestIndex) of $($totalTests): $($testFunction.Name)" -PercentComplete (($currentTestIndex / $totalTests) * 100) $functionName = $testFunction.BaseName if ($PSCmdlet.ShouldProcess($functionName, "Execute test")) { - $auditResult = Invoke-TestFunction -FunctionFile $testFunction -DomainName $DomainName + $auditResult = Invoke-TestFunction -FunctionFile $testFunction -DomainName $M365DomainForPWPolicyTest # Add the result to the collection [void]$allAuditResults.Add($auditResult) } diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index a4f9a07..7cf400a 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -2,9 +2,8 @@ function Test-PasswordNeverExpirePolicy { [CmdletBinding()] [OutputType([CISAuditResult])] param ( - # Aligned - [Parameter(Mandatory)] - [string]$DomainName # DomainName parameter is now mandatory + [Parameter(Mandatory = $false)] + [string]$DomainName ) begin { @@ -12,33 +11,58 @@ function Test-PasswordNeverExpirePolicy { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed $recnum = "1.3.1" + $overallResult = $true + $detailsList = @() + $failureReasonsList = @() + + # Add headers for the details + $detailsList += "Domain|Validity Period|IsDefault" } process { try { - # 1.3.1 (L1) Ensure the 'Password expiration policy' is set to 'Set passwords to never expire' - # Pass if PasswordValidityPeriodInDays is 0. Fail otherwise. - - # Retrieve password expiration policy - $passwordPolicy = Get-MgDomain -DomainId $DomainName | Select-Object -ExpandProperty PasswordValidityPeriodInDays - - # Prepare failure reasons and details based on compliance - $failureReasons = if ($passwordPolicy -ne 0) { - "Password expiration is not set to never expire" - } - else { - "N/A" + # Retrieve all domains or a specific domain + $domains = if ($DomainName) { + Get-MgDomain -DomainId $DomainName + } else { + Get-MgDomain } - $details = "Validity Period: $passwordPolicy days" + foreach ($domain in $domains) { + $domainName = $domain.Id + $isDefault = $domain.IsDefault + # Retrieve password expiration policy + $passwordPolicy = $domain.PasswordValidityPeriodInDays + + # Determine if the policy is compliant + $isCompliant = $passwordPolicy -eq 0 + $overallResult = $overallResult -and $isCompliant + + # Prepare failure reasons and details based on compliance + $failureReasons = if ($isCompliant) { + "N/A" + } 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" + } + + $details = "$domainName|$passwordPolicy days|$isDefault" + + # Add details and failure reasons to the lists + $detailsList += $details + $failureReasonsList += $failureReasons + } + + # Prepare the final failure reason and details + $finalFailureReason = $failureReasonsList -join "`n" + $finalDetails = $detailsList -join "`n" # Create and populate the CISAuditResult object $params = @{ Rec = $recnum - Result = $passwordPolicy -eq 0 - Status = if ($passwordPolicy -eq 0) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + Result = $overallResult + Status = if ($overallResult) { "Pass" } else { "Fail" } + Details = $finalDetails + FailureReason = $finalFailureReason } $auditResult = Initialize-CISAuditResult @params }