From 2027e8b21ba534748533e8493a2ceb4990c48539 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:04:18 -0500 Subject: [PATCH 01/45] Add: error handling to tests --- source/Private/Format-MissingActions.ps1 | 26 ++++ source/Private/Initialize-CISAuditResult.ps1 | 34 ++++-- .../Test-AdministrativeAccountCompliance.ps1 | 112 +++++++++--------- source/tests/Test-AntiPhishingPolicy.ps1 | 109 +++++++++-------- source/tests/Test-AuditDisabledFalse.ps1 | 59 +++++---- source/tests/Test-AuditLogSearch.ps1 | 61 ++++++---- source/tests/Test-BlockChannelEmails.ps1 | 12 +- source/tests/Test-BlockMailForwarding.ps1 | 60 ++++++---- .../tests/Test-BlockSharedMailboxSignIn.ps1 | 64 +++++----- source/tests/Test-CommonAttachmentFilter.ps1 | 59 +++++---- source/tests/Test-CustomerLockbox.ps1 | 12 +- source/tests/Test-DialInBypassLobby.ps1 | 60 ++++++---- .../Test-DisallowInfectedFilesDownload.ps1 | 61 ++++++---- source/tests/Test-EnableDKIM.ps1 | 12 +- source/tests/Test-ExternalNoControl.ps1 | 12 +- .../tests/Test-ExternalSharingCalendars.ps1 | 74 +++++++----- source/tests/Test-GlobalAdminsCount.ps1 | 60 ++++++---- source/tests/Test-GuestAccessExpiration.ps1 | 12 +- .../tests/Test-GuestUsersBiweeklyReview.ps1 | 61 ++++++---- source/tests/Test-IdentifyExternalEmail.ps1 | 50 ++++---- source/tests/Test-LinkSharingRestrictions.ps1 | 50 ++++---- source/tests/Test-MailTipsEnabled.ps1 | 61 ++++++---- source/tests/Test-MailboxAuditingE3.ps1 | 48 ++++---- source/tests/Test-MailboxAuditingE5.ps1 | 18 ++- .../Test-ManagedApprovedPublicGroups.ps1 | 60 ++++++---- source/tests/Test-MeetingChatNoAnonymous.ps1 | 51 ++++---- .../tests/Test-ModernAuthExchangeOnline.ps1 | 17 ++- source/tests/Test-ModernAuthSharePoint.ps1 | 47 +++++--- source/tests/Test-NoAnonymousMeetingJoin.ps1 | 11 +- source/tests/Test-NoAnonymousMeetingStart.ps1 | 49 ++++---- source/tests/Test-NoWhitelistDomains.ps1 | 59 +++++---- source/tests/Test-NotifyMalwareInternal.ps1 | 11 +- .../Test-OneDriveContentRestrictions.ps1 | 59 +++++---- .../tests/Test-OneDriveSyncRestrictions.ps1 | 59 +++++---- source/tests/Test-OrgOnlyBypassLobby.ps1 | 61 ++++++---- source/tests/Test-OrganizersPresent.ps1 | 11 +- source/tests/Test-PasswordHashSync.ps1 | 11 +- .../tests/Test-PasswordNeverExpirePolicy.ps1 | 49 ++++---- source/tests/Test-ReauthWithCode.ps1 | 49 ++++---- source/tests/Test-ReportSecurityInTeams.ps1 | 67 ++++++----- source/tests/Test-RestrictCustomScripts.ps1 | 75 ++++++------ source/tests/Test-RestrictExternalSharing.ps1 | 49 ++++---- source/tests/Test-RestrictOutlookAddins.ps1 | 95 ++++++++------- .../Test-RestrictStorageProvidersOutlook.ps1 | 11 +- source/tests/Test-RestrictTenantCreation.ps1 | 49 ++++---- source/tests/Test-SafeAttachmentsPolicy.ps1 | 59 +++++---- source/tests/Test-SafeAttachmentsTeams.ps1 | 71 ++++++----- source/tests/Test-SafeLinksOfficeApps.ps1 | 79 ++++++------ source/tests/Test-SharePointAADB2B.ps1 | 29 +++-- .../Test-SharePointExternalSharingDomains.ps1 | 31 +++-- .../Test-SharePointGuestsItemSharing.ps1 | 31 +++-- source/tests/Test-SpamPolicyAdminNotify.ps1 | 53 +++++---- source/tests/Test-TeamsExternalAccess.ps1 | 43 ++++--- .../tests/Test-TeamsExternalFileSharing.ps1 | 51 ++++---- 54 files changed, 1545 insertions(+), 1039 deletions(-) create mode 100644 source/Private/Format-MissingActions.ps1 diff --git a/source/Private/Format-MissingActions.ps1 b/source/Private/Format-MissingActions.ps1 new file mode 100644 index 0000000..b9efa97 --- /dev/null +++ b/source/Private/Format-MissingActions.ps1 @@ -0,0 +1,26 @@ +function Format-MissingActions { + param ([array]$missingActions) + + $actionGroups = @{ + "Admin" = @() + "Delegate" = @() + "Owner" = @() + } + + foreach ($action in $missingActions) { + if ($action -match "(Admin|Delegate|Owner) action '([^']+)' missing") { + $type = $matches[1] + $actionName = $matches[2] + $actionGroups[$type] += $actionName + } + } + + $formattedResults = @() + foreach ($type in $actionGroups.Keys) { + if ($actionGroups[$type].Count -gt 0) { + $formattedResults += "$($type) actions missing: $($actionGroups[$type] -join ', ')" + } + } + + return $formattedResults -join '; ' +} \ No newline at end of file diff --git a/source/Private/Initialize-CISAuditResult.ps1 b/source/Private/Initialize-CISAuditResult.ps1 index b1e2e09..3b2cc94 100644 --- a/source/Private/Initialize-CISAuditResult.ps1 +++ b/source/Private/Initialize-CISAuditResult.ps1 @@ -1,19 +1,23 @@ function Initialize-CISAuditResult { + [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Rec, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, ParameterSetName = 'Full')] [bool]$Result, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, ParameterSetName = 'Full')] [string]$Status, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, ParameterSetName = 'Full')] [string]$Details, - [Parameter(Mandatory = $true)] - [string]$FailureReason + [Parameter(Mandatory = $true, ParameterSetName = 'Full')] + [string]$FailureReason, + + [Parameter(ParameterSetName = 'Error')] + [switch]$Failure ) # Import the test definitions CSV file @@ -22,6 +26,10 @@ function Initialize-CISAuditResult { # Find the row that matches the provided recommendation (Rec) $testDefinition = $testDefinitions | Where-Object { $_.Rec -eq $Rec } + if (-not $testDefinition) { + throw "Test definition for recommendation '$Rec' not found." + } + # Create an instance of CISAuditResult and populate it $auditResult = [CISAuditResult]::new() $auditResult.Rec = $Rec @@ -36,10 +44,18 @@ function Initialize-CISAuditResult { $auditResult.Automated = [bool]::Parse($testDefinition.Automated) $auditResult.Connection = $testDefinition.Connection $auditResult.CISControlVer = 'v8' - $auditResult.Result = $Result - $auditResult.Status = $Status - $auditResult.Details = $Details - $auditResult.FailureReason = $FailureReason + + if ($PSCmdlet.ParameterSetName -eq 'Full') { + $auditResult.Result = $Result + $auditResult.Status = $Status + $auditResult.Details = $Details + $auditResult.FailureReason = $FailureReason + } elseif ($PSCmdlet.ParameterSetName -eq 'Error') { + $auditResult.Result = $false + $auditResult.Status = 'Fail' + $auditResult.Details = "An error occurred while processing the test." + $auditResult.FailureReason = "Initialization error: Failed to process the test." + } return $auditResult } diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 21ab959..05b3796 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -1,83 +1,89 @@ function Test-AdministrativeAccountCompliance { [CmdletBinding()] param ( - # Aligned # Parameters can be added if needed ) begin { - #. .\source\Classes\CISAuditResult.ps1 + # Initialize the valid licenses $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $recnum = "1.1.1" } process { - $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } - $adminRoleUsers = @() + try { + $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } + $adminRoleUsers = @() - foreach ($role in $adminRoles) { - $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" + foreach ($role in $adminRoles) { + $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" - foreach ($assignment in $roleAssignments) { - $userDetails = Get-MgUser -UserId $assignment.PrincipalId -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue - if ($userDetails) { - $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue - $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } + foreach ($assignment in $roleAssignments) { + $userDetails = Get-MgUser -UserId $assignment.PrincipalId -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue + if ($userDetails) { + $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue + $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } - $adminRoleUsers += [PSCustomObject]@{ - UserName = $userDetails.UserPrincipalName - RoleName = $role.DisplayName - UserId = $userDetails.Id - HybridUser = $userDetails.OnPremisesSyncEnabled - Licenses = $licenseString + $adminRoleUsers += [PSCustomObject]@{ + UserName = $userDetails.UserPrincipalName + RoleName = $role.DisplayName + UserId = $userDetails.Id + HybridUser = $userDetails.OnPremisesSyncEnabled + Licenses = $licenseString + } } } } - } - $uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object { - $first = $_.Group | Select-Object -First 1 - $roles = ($_.Group.RoleName -join ', ') - $licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique + $uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object { + $first = $_.Group | Select-Object -First 1 + $roles = ($_.Group.RoleName -join ', ') + $licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique - $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } } - } + $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } } + } - $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { - $_.HybridUser -or - -not ($_.Licenses -split '\|' | Where-Object { $validLicenses -contains $_ }) - } + $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { + $_.HybridUser -or + -not ($_.Licenses -split '\|' | Where-Object { $validLicenses -contains $_ }) + } - $failureReasons = $nonCompliantUsers | ForEach-Object { - $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } - $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } - "$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')" - } - $failureReasons = $failureReasons -join "`n" - $details = if ($nonCompliantUsers) { - "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" - } - else { - "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" - } + $failureReasons = $nonCompliantUsers | ForEach-Object { + $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } + $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } + "$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')" + } + $failureReasons = $failureReasons -join "`n" + $details = if ($nonCompliantUsers) { + "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" + } + else { + "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" + } - $result = $nonCompliantUsers.Count -eq 0 - $status = if ($result) { 'Pass' } else { 'Fail' } - $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" } + $result = $nonCompliantUsers.Count -eq 0 + $status = if ($result) { 'Pass' } else { 'Fail' } + $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" } - # Create the parameter splat - $params = @{ - Rec = "1.1.1" - Result = $result - Status = $status - Details = $details - FailureReason = $failureReason + # Create the parameter splat + $params = @{ + Rec = $recnum + Result = $result + Status = $status + Details = $details + FailureReason = $failureReason + } + + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $auditResult = Initialize-CISAuditResult @params + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } - end { - # Output the result return $auditResult } } diff --git a/source/tests/Test-AntiPhishingPolicy.ps1 b/source/tests/Test-AntiPhishingPolicy.ps1 index 88b103e..ccbf02f 100644 --- a/source/tests/Test-AntiPhishingPolicy.ps1 +++ b/source/tests/Test-AntiPhishingPolicy.ps1 @@ -10,66 +10,75 @@ function Test-AntiPhishingPolicy { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed #$auditResults = @() + $recnum = "2.1.7" } process { - # 2.1.7 Ensure that an anti-phishing policy has been created - # Retrieve and validate the anti-phishing policies - $antiPhishPolicies = Get-AntiPhishPolicy - $validatedPolicies = $antiPhishPolicies | Where-Object { - $_.Enabled -eq $true -and - $_.PhishThresholdLevel -ge 2 -and - $_.EnableMailboxIntelligenceProtection -eq $true -and - $_.EnableMailboxIntelligence -eq $true -and - $_.EnableSpoofIntelligence -eq $true - } + try { + # 2.1.7 Ensure that an anti-phishing policy has been created - # Check if there is at least one policy that meets the requirements - $nonCompliantItems = $antiPhishPolicies | Where-Object { - $_.Enabled -ne $true -or - $_.PhishThresholdLevel -lt 2 -or - $_.EnableMailboxIntelligenceProtection -ne $true -or - $_.EnableMailboxIntelligence -ne $true -or - $_.EnableSpoofIntelligence -ne $true - } - $compliantItems = $validatedPolicies - $isCompliant = $compliantItems.Count -gt 0 + # Retrieve and validate the anti-phishing policies + $antiPhishPolicies = Get-AntiPhishPolicy + $validatedPolicies = $antiPhishPolicies | Where-Object { + $_.Enabled -eq $true -and + $_.PhishThresholdLevel -ge 2 -and + $_.EnableMailboxIntelligenceProtection -eq $true -and + $_.EnableMailboxIntelligence -eq $true -and + $_.EnableSpoofIntelligence -eq $true + } - # Prepare failure reasons for non-compliant items - $nonCompliantNames = $nonCompliantItems | ForEach-Object { $_.Name } - $failureReasons = if ($nonCompliantNames.Count -gt 0) { - "Reason: Does not meet one or more compliance criteria.`nNon-compliant Policies:`n" + ($nonCompliantNames -join "`n") - } - else { - "N/A" - } + # Check if there is at least one policy that meets the requirements + $nonCompliantItems = $antiPhishPolicies | Where-Object { + $_.Enabled -ne $true -or + $_.PhishThresholdLevel -lt 2 -or + $_.EnableMailboxIntelligenceProtection -ne $true -or + $_.EnableMailboxIntelligence -ne $true -or + $_.EnableSpoofIntelligence -ne $true + } + $compliantItems = $validatedPolicies + $isCompliant = $compliantItems.Count -gt 0 - # Prepare details for non-compliant items - $nonCompliantDetails = $nonCompliantItems | ForEach-Object { - "Policy: $($_.Name)" - } - $nonCompliantDetails = $nonCompliantDetails -join "`n" + # Prepare failure reasons for non-compliant items + $nonCompliantNames = $nonCompliantItems | ForEach-Object { $_.Name } + $failureReasons = if ($nonCompliantNames.Count -gt 0) { + "Reason: Does not meet one or more compliance criteria.`nNon-compliant Policies:`n" + ($nonCompliantNames -join "`n") + } + else { + "N/A" + } - # Prepare details based on compliance - $details = if ($nonCompliantItems) { - "Non-Compliant Items: $($nonCompliantItems.Count)`nDetails:`n$nonCompliantDetails" - } - else { - "Compliant Items: $($compliantItems.Count)" - } + # Prepare details for non-compliant items + $nonCompliantDetails = $nonCompliantItems | ForEach-Object { + "Policy: $($_.Name)" + } + $nonCompliantDetails = $nonCompliantDetails -join "`n" - # Parameter splat for Initialize-CISAuditResult function - $params = @{ - Rec = "2.1.7" - Result = $nonCompliantItems.Count -eq 0 - Status = if ($isCompliant) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } + # Prepare details based on compliance + $details = if ($nonCompliantItems) { + "Non-Compliant Items: $($nonCompliantItems.Count)`nDetails:`n$nonCompliantDetails" + } + else { + "Compliant Items: $($compliantItems.Count)" + } - # Create and populate the CISAuditResult object - $auditResult = Initialize-CISAuditResult @params + # Parameter splat for Initialize-CISAuditResult function + $params = @{ + Rec = $recnum + Result = $nonCompliantItems.Count -eq 0 + Status = if ($isCompliant) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + + # Create and populate the CISAuditResult object + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-AuditDisabledFalse.ps1 b/source/tests/Test-AuditDisabledFalse.ps1 index 3f91a83..c2c2dcc 100644 --- a/source/tests/Test-AuditDisabledFalse.ps1 +++ b/source/tests/Test-AuditDisabledFalse.ps1 @@ -9,39 +9,48 @@ function Test-AuditDisabledFalse { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "6.1.1" } process { - # 6.1.1 (L1) Ensure 'AuditDisabled' organizationally is set to 'False' - # Retrieve the AuditDisabled configuration - $auditDisabledConfig = Get-OrganizationConfig | Select-Object AuditDisabled - $auditNotDisabled = -not $auditDisabledConfig.AuditDisabled + try { + # 6.1.1 (L1) Ensure 'AuditDisabled' organizationally is set to 'False' - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $auditNotDisabled) { - "AuditDisabled is set to True" - } - else { - "N/A" - } + # Retrieve the AuditDisabled configuration + $auditDisabledConfig = Get-OrganizationConfig | Select-Object AuditDisabled + $auditNotDisabled = -not $auditDisabledConfig.AuditDisabled - $details = if ($auditNotDisabled) { - "Audit is not disabled organizationally" - } - else { - "Audit is disabled organizationally" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $auditNotDisabled) { + "AuditDisabled is set to True" + } + else { + "N/A" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "6.1.1" - Result = $auditNotDisabled - Status = if ($auditNotDisabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + $details = if ($auditNotDisabled) { + "Audit is not disabled organizationally" + } + else { + "Audit is disabled organizationally" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $auditNotDisabled + Status = if ($auditNotDisabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-AuditLogSearch.ps1 b/source/tests/Test-AuditLogSearch.ps1 index 023f569..69f2c8f 100644 --- a/source/tests/Test-AuditLogSearch.ps1 +++ b/source/tests/Test-AuditLogSearch.ps1 @@ -9,40 +9,49 @@ function Test-AuditLogSearch { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "3.1.1" } process { - # 3.1.1 (L1) Ensure Microsoft 365 audit log search is Enabled - # Retrieve the audit log configuration - $auditLogConfig = Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled - $auditLogResult = $auditLogConfig.UnifiedAuditLogIngestionEnabled + try { + # 3.1.1 (L1) Ensure Microsoft 365 audit log search is Enabled - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $auditLogResult) { - "Audit log search is not enabled" - } - else { - "N/A" - } + # Retrieve the audit log configuration + $auditLogConfig = Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled + $auditLogResult = $auditLogConfig.UnifiedAuditLogIngestionEnabled - $details = if ($auditLogResult) { - "UnifiedAuditLogIngestionEnabled: True" - } - else { - "UnifiedAuditLogIngestionEnabled: False" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $auditLogResult) { + "Audit log search is not enabled" + } + else { + "N/A" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "3.1.1" - Result = $auditLogResult - Status = if ($auditLogResult) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params + $details = if ($auditLogResult) { + "UnifiedAuditLogIngestionEnabled: True" + } + else { + "UnifiedAuditLogIngestionEnabled: False" + } + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $auditLogResult + Status = if ($auditLogResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-BlockChannelEmails.ps1 b/source/tests/Test-BlockChannelEmails.ps1 index c8ed086..39884d7 100644 --- a/source/tests/Test-BlockChannelEmails.ps1 +++ b/source/tests/Test-BlockChannelEmails.ps1 @@ -9,9 +9,12 @@ function Test-BlockChannelEmails { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.1.2" } process { + + try { # 8.1.2 (L1) Ensure users can't send emails to a channel email address # Retrieve Teams client configuration @@ -35,13 +38,20 @@ function Test-BlockChannelEmails { # Create and populate the CISAuditResult object $params = @{ - Rec = "8.1.2" + Rec = $recnum Result = -not $allowEmailIntoChannel Status = if (-not $allowEmailIntoChannel) { "Pass" } else { "Fail" } Details = $details FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index 8039d06..5554b32 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -12,37 +12,45 @@ function Test-BlockMailForwarding { } process { - # 6.2.1 (L1) Ensure all forms of mail forwarding are blocked and/or disabled + try { + # 6.2.1 (L1) Ensure all forms of mail forwarding are blocked and/or disabled - # Retrieve the transport rules that redirect messages - $transportRules = Get-TransportRule | Where-Object { $null -ne $_.RedirectMessageTo } - $forwardingBlocked = $transportRules.Count -eq 0 + # Retrieve the transport rules that redirect messages + $transportRules = Get-TransportRule | Where-Object { $null -ne $_.RedirectMessageTo } + $forwardingBlocked = $transportRules.Count -eq 0 - # Prepare failure reasons and details based on compliance - $failureReasons = if ($transportRules.Count -gt 0) { - "Mail forwarding rules found: $($transportRules.Name -join ', ')" - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($transportRules.Count -gt 0) { + "Mail forwarding rules found: $($transportRules.Name -join ', ')" + } + else { + "N/A" + } - $details = if ($transportRules.Count -gt 0) { - $transportRules | ForEach-Object { - "$($_.Name) redirects to $($_.RedirectMessageTo)" - } -join " | " - } - else { - "Step 1: No forwarding rules found. Please proceed with Step 2 described in CIS Benchmark." - } + $details = if ($transportRules.Count -gt 0) { + $transportRules | ForEach-Object { + "$($_.Name) redirects to $($_.RedirectMessageTo)" + } -join " | " + } + else { + "Step 1: No forwarding rules found. Please proceed with Step 2 described in CIS Benchmark." + } - $params = @{ - Rec = "6.2.1" - Result = $forwardingBlocked - Status = if ($forwardingBlocked) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + $params = @{ + Rec = "6.2.1" + Result = $forwardingBlocked + Status = if ($forwardingBlocked) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec "6.2.1" -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-BlockSharedMailboxSignIn.ps1 b/source/tests/Test-BlockSharedMailboxSignIn.ps1 index 7f4711b..a8d763a 100644 --- a/source/tests/Test-BlockSharedMailboxSignIn.ps1 +++ b/source/tests/Test-BlockSharedMailboxSignIn.ps1 @@ -9,41 +9,51 @@ function Test-BlockSharedMailboxSignIn { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "1.2.2" } process { - # 1.2.2 (L1) Ensure sign-in to shared mailboxes is blocked - # Retrieve shared mailbox details - $MBX = Get-EXOMailbox -RecipientTypeDetails SharedMailbox - $sharedMailboxDetails = $MBX | ForEach-Object { Get-AzureADUser -ObjectId $_.ExternalDirectoryObjectId } - $enabledMailboxes = $sharedMailboxDetails | Where-Object { $_.AccountEnabled } | ForEach-Object { $_.DisplayName } - $allBlocked = $enabledMailboxes.Count -eq 0 + try { + # 1.2.2 (L1) Ensure sign-in to shared mailboxes is blocked - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $allBlocked) { - "Some mailboxes have sign-in enabled: $($enabledMailboxes -join ', ')" - } - else { - "N/A" - } + # Retrieve shared mailbox details + $MBX = Get-EXOMailbox -RecipientTypeDetails SharedMailbox + $sharedMailboxDetails = $MBX | ForEach-Object { Get-AzureADUser -ObjectId $_.ExternalDirectoryObjectId } + $enabledMailboxes = $sharedMailboxDetails | Where-Object { $_.AccountEnabled } | ForEach-Object { $_.DisplayName } + $allBlocked = $enabledMailboxes.Count -eq 0 - $details = if ($allBlocked) { - "All shared mailboxes have sign-in blocked." - } - else { - "Enabled Mailboxes: $($enabledMailboxes -join ', ')" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $allBlocked) { + "Some mailboxes have sign-in enabled: $($enabledMailboxes -join ', ')" + } + else { + "N/A" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "1.2.2" - Result = $allBlocked - Status = if ($allBlocked) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + $details = if ($allBlocked) { + "All shared mailboxes have sign-in blocked." + } + else { + "Enabled Mailboxes: $($enabledMailboxes -join ', ')" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $allBlocked + Status = if ($allBlocked) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-CommonAttachmentFilter.ps1 b/source/tests/Test-CommonAttachmentFilter.ps1 index 9b60797..b328491 100644 --- a/source/tests/Test-CommonAttachmentFilter.ps1 +++ b/source/tests/Test-CommonAttachmentFilter.ps1 @@ -9,39 +9,48 @@ function Test-CommonAttachmentFilter { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "2.1.2" } process { - # 2.1.2 (L1) Ensure the Common Attachment Types Filter is enabled + try { + # 2.1.2 (L1) Ensure the Common Attachment Types Filter is enabled - # Retrieve the attachment filter policy - $attachmentFilter = Get-MalwareFilterPolicy -Identity Default | Select-Object EnableFileFilter - $result = $attachmentFilter.EnableFileFilter + # Retrieve the attachment filter policy + $attachmentFilter = Get-MalwareFilterPolicy -Identity Default | Select-Object EnableFileFilter + $result = $attachmentFilter.EnableFileFilter - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $result) { - "Common Attachment Types Filter is disabled" - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $result) { + "Common Attachment Types Filter is disabled" + } + else { + "N/A" + } - $details = if ($result) { - "File Filter Enabled: True" - } - else { - "File Filter Enabled: False" - } + $details = if ($result) { + "File Filter Enabled: True" + } + else { + "File Filter Enabled: False" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "2.1.2" - Result = $result - Status = if ($result) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-CustomerLockbox.ps1 b/source/tests/Test-CustomerLockbox.ps1 index c0723f9..a540f1b 100644 --- a/source/tests/Test-CustomerLockbox.ps1 +++ b/source/tests/Test-CustomerLockbox.ps1 @@ -9,9 +9,12 @@ function Test-CustomerLockbox { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "1.3.6" } process { + + try { # 1.3.6 (L2) Ensure the customer lockbox feature is enabled # Retrieve the organization configuration @@ -35,13 +38,20 @@ function Test-CustomerLockbox { # Create and populate the CISAuditResult object # $params = @{ - Rec = "1.3.6" + Rec = $recnum Result = $customerLockboxEnabled Status = if ($customerLockboxEnabled) { "Pass" } else { "Fail" } Details = $details FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-DialInBypassLobby.ps1 b/source/tests/Test-DialInBypassLobby.ps1 index dd2a47b..efd83fa 100644 --- a/source/tests/Test-DialInBypassLobby.ps1 +++ b/source/tests/Test-DialInBypassLobby.ps1 @@ -9,39 +9,49 @@ function Test-DialInBypassLobby { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.5.4" } process { - # 8.5.4 (L1) Ensure users dialing in can't bypass the lobby - # Retrieve Teams meeting policy for PSTN users - $CsTeamsMeetingPolicyPSTN = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowPSTNUsersToBypassLobby - $PSTNBypassDisabled = -not $CsTeamsMeetingPolicyPSTN.AllowPSTNUsersToBypassLobby + try { + # 8.5.4 (L1) Ensure users dialing in can't bypass the lobby - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $PSTNBypassDisabled) { - "Users dialing in can bypass the lobby" - } - else { - "N/A" - } + # Retrieve Teams meeting policy for PSTN users + $CsTeamsMeetingPolicyPSTN = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowPSTNUsersToBypassLobby + $PSTNBypassDisabled = -not $CsTeamsMeetingPolicyPSTN.AllowPSTNUsersToBypassLobby - $details = if ($PSTNBypassDisabled) { - "AllowPSTNUsersToBypassLobby is set to False" - } - else { - "AllowPSTNUsersToBypassLobby is set to True" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $PSTNBypassDisabled) { + "Users dialing in can bypass the lobby" + } + else { + "N/A" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "8.5.4" - Result = $PSTNBypassDisabled - Status = if ($PSTNBypassDisabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + $details = if ($PSTNBypassDisabled) { + "AllowPSTNUsersToBypassLobby is set to False" + } + else { + "AllowPSTNUsersToBypassLobby is set to True" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $PSTNBypassDisabled + Status = if ($PSTNBypassDisabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-DisallowInfectedFilesDownload.ps1 b/source/tests/Test-DisallowInfectedFilesDownload.ps1 index 3ce9b3a..963813d 100644 --- a/source/tests/Test-DisallowInfectedFilesDownload.ps1 +++ b/source/tests/Test-DisallowInfectedFilesDownload.ps1 @@ -10,40 +10,49 @@ function Test-DisallowInfectedFilesDownload { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.3.1" } process { - # 7.3.1 (L2) Ensure Office 365 SharePoint infected files are disallowed for download - # Retrieve the SharePoint tenant configuration - $SPOTenantDisallowInfectedFileDownload = Get-SPOTenant | Select-Object DisallowInfectedFileDownload - $isDisallowInfectedFileDownloadEnabled = $SPOTenantDisallowInfectedFileDownload.DisallowInfectedFileDownload + try { + # 7.3.1 (L2) Ensure Office 365 SharePoint infected files are disallowed for download - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $isDisallowInfectedFileDownloadEnabled) { - "Downloading infected files is not disallowed." - } - else { - "N/A" - } + # Retrieve the SharePoint tenant configuration + $SPOTenantDisallowInfectedFileDownload = Get-SPOTenant | Select-Object DisallowInfectedFileDownload + $isDisallowInfectedFileDownloadEnabled = $SPOTenantDisallowInfectedFileDownload.DisallowInfectedFileDownload - $details = if ($isDisallowInfectedFileDownloadEnabled) { - "DisallowInfectedFileDownload: True" - } - else { - "DisallowInfectedFileDownload: False" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isDisallowInfectedFileDownloadEnabled) { + "Downloading infected files is not disallowed." + } + else { + "N/A" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.3.1" - Result = $isDisallowInfectedFileDownloadEnabled - Status = if ($isDisallowInfectedFileDownloadEnabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params + $details = if ($isDisallowInfectedFileDownloadEnabled) { + "DisallowInfectedFileDownload: True" + } + else { + "DisallowInfectedFileDownload: False" + } + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isDisallowInfectedFileDownloadEnabled + Status = if ($isDisallowInfectedFileDownloadEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-EnableDKIM.ps1 b/source/tests/Test-EnableDKIM.ps1 index db7bac6..7661073 100644 --- a/source/tests/Test-EnableDKIM.ps1 +++ b/source/tests/Test-EnableDKIM.ps1 @@ -9,9 +9,12 @@ function Test-EnableDKIM { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "2.1.9" } process { + + try { # 2.1.9 (L1) Ensure DKIM is enabled for all Exchange Online Domains # Retrieve DKIM configuration for all domains @@ -36,13 +39,20 @@ function Test-EnableDKIM { # Create and populate the CISAuditResult object $params = @{ - Rec = "2.1.9" + Rec = $recnum Result = $dkimResult Status = if ($dkimResult) { "Pass" } else { "Fail" } Details = $details FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-ExternalNoControl.ps1 b/source/tests/Test-ExternalNoControl.ps1 index 8d52da7..0afec63 100644 --- a/source/tests/Test-ExternalNoControl.ps1 +++ b/source/tests/Test-ExternalNoControl.ps1 @@ -10,9 +10,12 @@ function Test-ExternalNoControl { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.5.7" } process { + + try { # 8.5.7 (L1) Ensure external participants can't give or request control # Retrieve Teams meeting policy for external participant control @@ -36,13 +39,20 @@ function Test-ExternalNoControl { # Create and populate the CISAuditResult object $params = @{ - Rec = "8.5.7" + Rec = $recnum Result = $externalControlRestricted Status = if ($externalControlRestricted) { "Pass" } else { "Fail" } Details = $details FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-ExternalSharingCalendars.ps1 b/source/tests/Test-ExternalSharingCalendars.ps1 index 9053bbb..2685a5c 100644 --- a/source/tests/Test-ExternalSharingCalendars.ps1 +++ b/source/tests/Test-ExternalSharingCalendars.ps1 @@ -10,48 +10,58 @@ function Test-ExternalSharingCalendars { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "1.3.3" } process { - # 1.3.3 (L2) Ensure 'External sharing' of calendars is not available (Automated) - # Retrieve sharing policies related to calendar sharing - $sharingPolicies = Get-SharingPolicy | Where-Object { $_.Domains -like '*CalendarSharing*' } + try { + # 1.3.3 (L2) Ensure 'External sharing' of calendars is not available (Automated) - # Check if calendar sharing is disabled in all applicable policies - $isExternalSharingDisabled = $true - $sharingPolicyDetails = @() - foreach ($policy in $sharingPolicies) { - if ($policy.Enabled -eq $true) { - $isExternalSharingDisabled = $false - $sharingPolicyDetails += "$($policy.Name): Enabled" + # Retrieve sharing policies related to calendar sharing + $sharingPolicies = Get-SharingPolicy | Where-Object { $_.Domains -like '*CalendarSharing*' } + + # Check if calendar sharing is disabled in all applicable policies + $isExternalSharingDisabled = $true + $sharingPolicyDetails = @() + foreach ($policy in $sharingPolicies) { + if ($policy.Enabled -eq $true) { + $isExternalSharingDisabled = $false + $sharingPolicyDetails += "$($policy.Name): Enabled" + } } - } - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $isExternalSharingDisabled) { - "Calendar sharing with external users is enabled in one or more policies." - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isExternalSharingDisabled) { + "Calendar sharing with external users is enabled in one or more policies." + } + else { + "N/A" + } - $details = if ($isExternalSharingDisabled) { - "Calendar sharing with external users is disabled." - } - else { - "Enabled Sharing Policies: $($sharingPolicyDetails -join ', ')" - } + $details = if ($isExternalSharingDisabled) { + "Calendar sharing with external users is disabled." + } + else { + "Enabled Sharing Policies: $($sharingPolicyDetails -join ', ')" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "1.3.3" - Result = $isExternalSharingDisabled - Status = if ($isExternalSharingDisabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isExternalSharingDisabled + Status = if ($isExternalSharingDisabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index c57110f..ea39bfd 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -10,39 +10,49 @@ function Test-GlobalAdminsCount { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "1.1.3" } process { - # 1.1.3 (L1) Ensure that between two and four global admins are designated - # Retrieve global admin role and members - $globalAdminRole = Get-MgDirectoryRole -Filter "RoleTemplateId eq '62e90394-69f5-4237-9190-012177145e10'" - $globalAdmins = Get-MgDirectoryRoleMember -DirectoryRoleId $globalAdminRole.Id - $globalAdminCount = $globalAdmins.AdditionalProperties.Count - $globalAdminUsernames = ($globalAdmins | ForEach-Object { $_.AdditionalProperties["displayName"] }) -join ', ' + try { + # 1.1.3 (L1) Ensure that between two and four global admins are designated - # Prepare failure reasons and details based on compliance - $failureReasons = if ($globalAdminCount -lt 2) { - "Less than 2 global admins: $globalAdminUsernames" - } - elseif ($globalAdminCount -gt 4) { - "More than 4 global admins: $globalAdminUsernames" - } - else { - "N/A" - } + # Retrieve global admin role and members + $globalAdminRole = Get-MgDirectoryRole -Filter "RoleTemplateId eq '62e90394-69f5-4237-9190-012177145e10'" + $globalAdmins = Get-MgDirectoryRoleMember -DirectoryRoleId $globalAdminRole.Id + $globalAdminCount = $globalAdmins.AdditionalProperties.Count + $globalAdminUsernames = ($globalAdmins | ForEach-Object { $_.AdditionalProperties["displayName"] }) -join ', ' - $details = "Count: $globalAdminCount; Users: $globalAdminUsernames" + # Prepare failure reasons and details based on compliance + $failureReasons = if ($globalAdminCount -lt 2) { + "Less than 2 global admins: $globalAdminUsernames" + } + elseif ($globalAdminCount -gt 4) { + "More than 4 global admins: $globalAdminUsernames" + } + else { + "N/A" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "1.1.3" - Result = $globalAdminCount -ge 2 -and $globalAdminCount -le 4 - Status = if ($globalAdminCount -ge 2 -and $globalAdminCount -le 4) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + $details = "Count: $globalAdminCount; Users: $globalAdminUsernames" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $globalAdminCount -ge 2 -and $globalAdminCount -le 4 + Status = if ($globalAdminCount -ge 2 -and $globalAdminCount -le 4) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-GuestAccessExpiration.ps1 b/source/tests/Test-GuestAccessExpiration.ps1 index 4a0b2b6..4f4aaca 100644 --- a/source/tests/Test-GuestAccessExpiration.ps1 +++ b/source/tests/Test-GuestAccessExpiration.ps1 @@ -10,9 +10,12 @@ function Test-GuestAccessExpiration { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.2.9" } process { + + try { # 7.2.9 (L1) Ensure guest access to a site or OneDrive will expire automatically # Retrieve SharePoint tenant settings related to guest access expiration @@ -31,13 +34,20 @@ function Test-GuestAccessExpiration { # Create and populate the CISAuditResult object $params = @{ - Rec = "7.2.9" + Rec = $recnum Result = $isGuestAccessExpirationConfiguredCorrectly Status = if ($isGuestAccessExpirationConfiguredCorrectly) { "Pass" } else { "Fail" } Details = $details FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-GuestUsersBiweeklyReview.ps1 b/source/tests/Test-GuestUsersBiweeklyReview.ps1 index 730f039..23b2d74 100644 --- a/source/tests/Test-GuestUsersBiweeklyReview.ps1 +++ b/source/tests/Test-GuestUsersBiweeklyReview.ps1 @@ -10,41 +10,50 @@ function Test-GuestUsersBiweeklyReview { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "1.1.4" } process { - # 1.1.4 (L1) Ensure Guest Users are reviewed at least biweekly + try { + # 1.1.4 (L1) Ensure Guest Users are reviewed at least biweekly - # Retrieve guest users from Microsoft Graph - # Connect-MgGraph -Scopes "User.Read.All" - $guestUsers = Get-MgUser -All -Filter "UserType eq 'Guest'" + # Retrieve guest users from Microsoft Graph + # Connect-MgGraph -Scopes "User.Read.All" + $guestUsers = Get-MgUser -All -Filter "UserType eq 'Guest'" - # Prepare failure reasons and details based on compliance - $failureReasons = if ($guestUsers) { - "Guest users present: $($guestUsers.Count)" - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($guestUsers) { + "Guest users present: $($guestUsers.Count)" + } + else { + "N/A" + } - $details = if ($guestUsers) { - $auditCommand = "Get-MgUser -All -Property UserType,UserPrincipalName | Where {`$_.UserType -ne 'Member'} | Format-Table UserPrincipalName, UserType" - "Manual review required. To list guest users, run: `"$auditCommand`"." - } - else { - "No guest users found." - } + $details = if ($guestUsers) { + $auditCommand = "Get-MgUser -All -Property UserType,UserPrincipalName | Where {`$_.UserType -ne 'Member'} | Format-Table UserPrincipalName, UserType" + "Manual review required. To list guest users, run: `"$auditCommand`"." + } + else { + "No guest users found." + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "1.1.4" - Result = -not $guestUsers - Status = if ($guestUsers) { "Fail" } else { "Pass" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = -not $guestUsers + Status = if ($guestUsers) { "Fail" } else { "Pass" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-IdentifyExternalEmail.ps1 b/source/tests/Test-IdentifyExternalEmail.ps1 index 623d986..e275bc1 100644 --- a/source/tests/Test-IdentifyExternalEmail.ps1 +++ b/source/tests/Test-IdentifyExternalEmail.ps1 @@ -10,34 +10,44 @@ function Test-IdentifyExternalEmail { #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "6.2.3" } process { - # 6.2.3 (L1) Ensure email from external senders is identified - # Retrieve external sender tagging configuration - $externalInOutlook = Get-ExternalInOutlook - $externalTaggingEnabled = ($externalInOutlook | ForEach-Object { $_.Enabled }) -contains $true + try { + # 6.2.3 (L1) Ensure email from external senders is identified - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $externalTaggingEnabled) { - "External sender tagging is disabled" - } - else { - "N/A" + # Retrieve external sender tagging configuration + $externalInOutlook = Get-ExternalInOutlook + $externalTaggingEnabled = ($externalInOutlook | ForEach-Object { $_.Enabled }) -contains $true + + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $externalTaggingEnabled) { + "External sender tagging is disabled" + } + else { + "N/A" + } + + $details = "Enabled: $($externalTaggingEnabled); AllowList: $($externalInOutlook.AllowList)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $externalTaggingEnabled + Status = if ($externalTaggingEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "Enabled: $($externalTaggingEnabled); AllowList: $($externalInOutlook.AllowList)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "6.2.3" - Result = $externalTaggingEnabled - Status = if ($externalTaggingEnabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-LinkSharingRestrictions.ps1 b/source/tests/Test-LinkSharingRestrictions.ps1 index b117da3..ad106bf 100644 --- a/source/tests/Test-LinkSharingRestrictions.ps1 +++ b/source/tests/Test-LinkSharingRestrictions.ps1 @@ -10,34 +10,44 @@ function Test-LinkSharingRestrictions { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.2.7" } process { - # 7.2.7 (L1) Ensure link sharing is restricted in SharePoint and OneDrive + try { + # 7.2.7 (L1) Ensure link sharing is restricted in SharePoint and OneDrive - # Retrieve link sharing configuration for SharePoint and OneDrive - $SPOTenantLinkSharing = Get-SPOTenant | Select-Object DefaultSharingLinkType - $isLinkSharingRestricted = $SPOTenantLinkSharing.DefaultSharingLinkType -eq 'Direct' # Or 'SpecificPeople' as per the recommendation + # Retrieve link sharing configuration for SharePoint and OneDrive + $SPOTenantLinkSharing = Get-SPOTenant | Select-Object DefaultSharingLinkType + $isLinkSharingRestricted = $SPOTenantLinkSharing.DefaultSharingLinkType -eq 'Direct' # Or 'SpecificPeople' as per the recommendation + + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isLinkSharingRestricted) { + "Link sharing is not restricted to 'Specific people'. Current setting: $($SPOTenantLinkSharing.DefaultSharingLinkType)" + } + else { + "N/A" + } + + $details = "DefaultSharingLinkType: $($SPOTenantLinkSharing.DefaultSharingLinkType)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isLinkSharingRestricted + Status = if ($isLinkSharingRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $isLinkSharingRestricted) { - "Link sharing is not restricted to 'Specific people'. Current setting: $($SPOTenantLinkSharing.DefaultSharingLinkType)" - } - else { - "N/A" } + catch { + Write-Error "An error occurred during the test: $_" - $details = "DefaultSharingLinkType: $($SPOTenantLinkSharing.DefaultSharingLinkType)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.2.7" - Result = $isLinkSharingRestricted - Status = if ($isLinkSharingRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-MailTipsEnabled.ps1 b/source/tests/Test-MailTipsEnabled.ps1 index 12224c0..d6c2684 100644 --- a/source/tests/Test-MailTipsEnabled.ps1 +++ b/source/tests/Test-MailTipsEnabled.ps1 @@ -11,40 +11,49 @@ function Test-MailTipsEnabled { # Initialization code, if needed $auditResult = [CISAuditResult]::new() + $recnum = "6.5.2" } process { - # 6.5.2 (L2) Ensure MailTips are enabled for end users + try { + # 6.5.2 (L2) Ensure MailTips are enabled for end users - # Retrieve organization configuration for MailTips settings - $orgConfig = Get-OrganizationConfig | Select-Object MailTipsAllTipsEnabled, MailTipsExternalRecipientsTipsEnabled, MailTipsGroupMetricsEnabled, MailTipsLargeAudienceThreshold - $allTipsEnabled = $orgConfig.MailTipsAllTipsEnabled -and $orgConfig.MailTipsGroupMetricsEnabled -and $orgConfig.MailTipsLargeAudienceThreshold -eq 25 - $externalRecipientsTipsEnabled = $orgConfig.MailTipsExternalRecipientsTipsEnabled + # Retrieve organization configuration for MailTips settings + $orgConfig = Get-OrganizationConfig | Select-Object MailTipsAllTipsEnabled, MailTipsExternalRecipientsTipsEnabled, MailTipsGroupMetricsEnabled, MailTipsLargeAudienceThreshold + $allTipsEnabled = $orgConfig.MailTipsAllTipsEnabled -and $orgConfig.MailTipsGroupMetricsEnabled -and $orgConfig.MailTipsLargeAudienceThreshold -eq 25 + $externalRecipientsTipsEnabled = $orgConfig.MailTipsExternalRecipientsTipsEnabled - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not ($allTipsEnabled -and $externalRecipientsTipsEnabled)) { - "One or more MailTips settings are not configured as required." - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not ($allTipsEnabled -and $externalRecipientsTipsEnabled)) { + "One or more MailTips settings are not configured as required." + } + else { + "N/A" + } - $details = if ($allTipsEnabled -and $externalRecipientsTipsEnabled) { - "MailTipsAllTipsEnabled: $($orgConfig.MailTipsAllTipsEnabled); MailTipsExternalRecipientsTipsEnabled: $($orgConfig.MailTipsExternalRecipientsTipsEnabled); MailTipsGroupMetricsEnabled: $($orgConfig.MailTipsGroupMetricsEnabled); MailTipsLargeAudienceThreshold: $($orgConfig.MailTipsLargeAudienceThreshold)" - } - else { - "One or more MailTips settings are not configured as required." - } + $details = if ($allTipsEnabled -and $externalRecipientsTipsEnabled) { + "MailTipsAllTipsEnabled: $($orgConfig.MailTipsAllTipsEnabled); MailTipsExternalRecipientsTipsEnabled: $($orgConfig.MailTipsExternalRecipientsTipsEnabled); MailTipsGroupMetricsEnabled: $($orgConfig.MailTipsGroupMetricsEnabled); MailTipsLargeAudienceThreshold: $($orgConfig.MailTipsLargeAudienceThreshold)" + } + else { + "One or more MailTips settings are not configured as required." + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "6.5.2" - Result = $allTipsEnabled -and $externalRecipientsTipsEnabled - Status = if ($allTipsEnabled -and $externalRecipientsTipsEnabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $allTipsEnabled -and $externalRecipientsTipsEnabled + Status = if ($allTipsEnabled -and $externalRecipientsTipsEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index 79373b7..eac96d6 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -19,15 +19,17 @@ function Test-MailboxAuditingE3 { $allFailures = @() $allUsers = Get-AzureADUser -All $true $processedUsers = @{} # Dictionary to track processed users + $recnum = "6.1.2" } process { - foreach ($user in $allUsers) { - if ($processedUsers.ContainsKey($user.UserPrincipalName)) { - Write-Verbose "Skipping already processed user: $($user.UserPrincipalName)" - continue - } - try { + try { + foreach ($user in $allUsers) { + if ($processedUsers.ContainsKey($user.UserPrincipalName)) { + Write-Verbose "Skipping already processed user: $($user.UserPrincipalName)" + continue + } + $licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName $hasOfficeE3 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e3SkuPartNumbers }).Count -gt 0 Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E3 license." @@ -61,24 +63,28 @@ function Test-MailboxAuditingE3 { $processedUsers[$user.UserPrincipalName] = $true } } - catch { - Write-Warning "Could not retrieve license details for user $($user.UserPrincipalName): $_" + + # Prepare failure reasons and details based on compliance + $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } + $details = if ($allFailures.Count -eq 0) { "All Office E3 users have correct mailbox audit settings." } else { $allFailures -join " | " } + + # Populate the audit result + $params = @{ + Rec = $recnum + Result = $allFailures.Count -eq 0 + Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons } - } + $auditResult = Initialize-CISAuditResult @params - # Prepare failure reasons and details based on compliance - $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } - $details = if ($allFailures.Count -eq 0) { "All Office E3 users have correct mailbox audit settings." } else { $allFailures -join " | " } - - # Populate the audit result - $params = @{ - Rec = "6.1.2" - Result = $allFailures.Count -eq 0 - Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons } - $auditResult = Initialize-CISAuditResult @params + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index 8f6796c..3c5e949 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -20,15 +20,17 @@ function Test-MailboxAuditingE5 { $allFailures = @() $allUsers = Get-AzureADUser -All $true $processedUsers = @{} # Dictionary to track processed users + $recnum = "6.1.3" } process { + try { foreach ($user in $allUsers) { if ($processedUsers.ContainsKey($user.UserPrincipalName)) { continue } - try { + $licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName $hasOfficeE5 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e5SkuPartNumbers }).Count -gt 0 Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E5 license." @@ -66,10 +68,7 @@ function Test-MailboxAuditingE5 { # Adding verbose output to indicate the user does not have an E5 license Write-Verbose "User $($user.UserPrincipalName) does not have an Office E5 license." } - } - catch { - Write-Warning "Could not retrieve license details for user $($user.UserPrincipalName): $_" - } + } # Prepare failure reasons and details based on compliance @@ -78,7 +77,7 @@ function Test-MailboxAuditingE5 { # Populate the audit result $params = @{ - Rec = "6.1.3" + Rec = $recnum Result = $allFailures.Count -eq 0 Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" } Details = $details @@ -86,6 +85,13 @@ function Test-MailboxAuditingE5 { } $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } + } end { return $auditResult diff --git a/source/tests/Test-ManagedApprovedPublicGroups.ps1 b/source/tests/Test-ManagedApprovedPublicGroups.ps1 index 80fb4fa..d471042 100644 --- a/source/tests/Test-ManagedApprovedPublicGroups.ps1 +++ b/source/tests/Test-ManagedApprovedPublicGroups.ps1 @@ -9,40 +9,48 @@ function Test-ManagedApprovedPublicGroups { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed - + $recnum = "1.2.1" } process { - # 1.2.1 (L2) Ensure that only organizationally managed/approved public groups exist (Automated) + try { + # 1.2.1 (L2) Ensure that only organizationally managed/approved public groups exist (Automated) - # Retrieve all public groups - $allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq "Public" } | Select-Object DisplayName, Visibility + # Retrieve all public groups + $allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq "Public" } | Select-Object DisplayName, Visibility - # Prepare failure reasons and details based on compliance - $failureReasons = if ($null -ne $allGroups -and $allGroups.Count -gt 0) { - "There are public groups present that are not organizationally managed/approved." - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($null -ne $allGroups -and $allGroups.Count -gt 0) { + "There are public groups present that are not organizationally managed/approved." + } + else { + "N/A" + } - $details = if ($null -eq $allGroups -or $allGroups.Count -eq 0) { - "No public groups found." - } - else { - $groupDetails = $allGroups | ForEach-Object { $_.DisplayName + " (" + $_.Visibility + ")" } - "Public groups found: $($groupDetails -join ', ')" - } + $details = if ($null -eq $allGroups -or $allGroups.Count -eq 0) { + "No public groups found." + } + else { + $groupDetails = $allGroups | ForEach-Object { $_.DisplayName + " (" + $_.Visibility + ")" } + "Public groups found: $($groupDetails -join ', ')" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "1.2.1" - Result = $null -eq $allGroups -or $allGroups.Count -eq 0 - Status = if ($null -eq $allGroups -or $allGroups.Count -eq 0) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $null -eq $allGroups -or $allGroups.Count -eq 0 + Status = if ($null -eq $allGroups -or $allGroups.Count -eq 0) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-MeetingChatNoAnonymous.ps1 b/source/tests/Test-MeetingChatNoAnonymous.ps1 index 29428b1..b7f1f98 100644 --- a/source/tests/Test-MeetingChatNoAnonymous.ps1 +++ b/source/tests/Test-MeetingChatNoAnonymous.ps1 @@ -9,36 +9,45 @@ function Test-MeetingChatNoAnonymous { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.5.5" } process { - # 8.5.5 (L2) Ensure meeting chat does not allow anonymous users + try { + # 8.5.5 (L2) Ensure meeting chat does not allow anonymous users - # Connect to Teams PowerShell using Connect-MicrosoftTeams + # Connect to Teams PowerShell using Connect-MicrosoftTeams - # Retrieve the Teams meeting policy for meeting chat - $CsTeamsMeetingPolicyChat = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property MeetingChatEnabledType - $chatAnonDisabled = $CsTeamsMeetingPolicyChat.MeetingChatEnabledType -eq 'EnabledExceptAnonymous' + # Retrieve the Teams meeting policy for meeting chat + $CsTeamsMeetingPolicyChat = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property MeetingChatEnabledType + $chatAnonDisabled = $CsTeamsMeetingPolicyChat.MeetingChatEnabledType -eq 'EnabledExceptAnonymous' - # Prepare failure reasons and details based on compliance - $failureReasons = if ($chatAnonDisabled) { - "N/A" - } - else { - "Meeting chat allows anonymous users" + # Prepare failure reasons and details based on compliance + $failureReasons = if ($chatAnonDisabled) { + "N/A" + } + else { + "Meeting chat allows anonymous users" + } + + $details = "MeetingChatEnabledType is set to $($CsTeamsMeetingPolicyChat.MeetingChatEnabledType)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $chatAnonDisabled + Status = if ($chatAnonDisabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "MeetingChatEnabledType is set to $($CsTeamsMeetingPolicyChat.MeetingChatEnabledType)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "8.5.5" - Result = $chatAnonDisabled - Status = if ($chatAnonDisabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-ModernAuthExchangeOnline.ps1 b/source/tests/Test-ModernAuthExchangeOnline.ps1 index 811679b..5210b18 100644 --- a/source/tests/Test-ModernAuthExchangeOnline.ps1 +++ b/source/tests/Test-ModernAuthExchangeOnline.ps1 @@ -9,6 +9,7 @@ function Test-ModernAuthExchangeOnline { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "6.5.1" } process { @@ -30,18 +31,22 @@ function Test-ModernAuthExchangeOnline { # Create and populate the CISAuditResult object $params = @{ - Rec = "6.5.1" - Result = $orgConfig.OAuth2ClientProfileEnabled - Status = if ($orgConfig.OAuth2ClientProfileEnabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + Rec = $recnum + Result = $orgConfig.OAuth2ClientProfileEnabled + Status = if ($orgConfig.OAuth2ClientProfileEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params } catch { - Write-Error "An error occurred while testing modern authentication for Exchange Online: $_" + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } + } end { diff --git a/source/tests/Test-ModernAuthSharePoint.ps1 b/source/tests/Test-ModernAuthSharePoint.ps1 index 3f7ae76..cb51f46 100644 --- a/source/tests/Test-ModernAuthSharePoint.ps1 +++ b/source/tests/Test-ModernAuthSharePoint.ps1 @@ -9,32 +9,41 @@ function Test-ModernAuthSharePoint { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.2.1" } process { - # 7.2.1 (L1) Ensure modern authentication for SharePoint applications is required - $SPOTenant = Get-SPOTenant | Select-Object -Property LegacyAuthProtocolsEnabled - $modernAuthForSPRequired = -not $SPOTenant.LegacyAuthProtocolsEnabled + try { + # 7.2.1 (L1) Ensure modern authentication for SharePoint applications is required + $SPOTenant = Get-SPOTenant | Select-Object -Property LegacyAuthProtocolsEnabled + $modernAuthForSPRequired = -not $SPOTenant.LegacyAuthProtocolsEnabled - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $modernAuthForSPRequired) { - "Legacy authentication protocols are enabled" - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $modernAuthForSPRequired) { + "Legacy authentication protocols are enabled" + } + else { + "N/A" + } - $details = "LegacyAuthProtocolsEnabled: $($SPOTenant.LegacyAuthProtocolsEnabled)" + $details = "LegacyAuthProtocolsEnabled: $($SPOTenant.LegacyAuthProtocolsEnabled)" - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.2.1" - Result = $modernAuthForSPRequired - Status = if ($modernAuthForSPRequired) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $modernAuthForSPRequired + Status = if ($modernAuthForSPRequired) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-NoAnonymousMeetingJoin.ps1 b/source/tests/Test-NoAnonymousMeetingJoin.ps1 index fbeb7dd..ce430ca 100644 --- a/source/tests/Test-NoAnonymousMeetingJoin.ps1 +++ b/source/tests/Test-NoAnonymousMeetingJoin.ps1 @@ -9,9 +9,11 @@ function Test-NoAnonymousMeetingJoin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.5.1" } process { + try { # 8.5.1 (L2) Ensure anonymous users can't join a meeting # Connect to Teams PowerShell using Connect-MicrosoftTeams @@ -31,7 +33,7 @@ function Test-NoAnonymousMeetingJoin { # Create and populate the CISAuditResult object $params = @{ - Rec = "8.5.1" + Rec = $recnum Result = -not $allowAnonymousUsersToJoinMeeting Status = if (-not $allowAnonymousUsersToJoinMeeting) { "Pass" } else { "Fail" } Details = $details @@ -39,6 +41,13 @@ function Test-NoAnonymousMeetingJoin { } $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } + } end { # Return the audit result diff --git a/source/tests/Test-NoAnonymousMeetingStart.ps1 b/source/tests/Test-NoAnonymousMeetingStart.ps1 index 01c680f..d9d1441 100644 --- a/source/tests/Test-NoAnonymousMeetingStart.ps1 +++ b/source/tests/Test-NoAnonymousMeetingStart.ps1 @@ -9,35 +9,44 @@ function Test-NoAnonymousMeetingStart { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.5.2" } process { - # 8.5.2 (L1) Ensure anonymous users and dial-in callers can't start a meeting + try { + # 8.5.2 (L1) Ensure anonymous users and dial-in callers can't start a meeting - # Connect to Teams PowerShell using Connect-MicrosoftTeams + # Connect to Teams PowerShell using Connect-MicrosoftTeams - $CsTeamsMeetingPolicyAnonymous = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowAnonymousUsersToStartMeeting - $anonymousStartDisabled = -not $CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting + $CsTeamsMeetingPolicyAnonymous = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowAnonymousUsersToStartMeeting + $anonymousStartDisabled = -not $CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting - # Prepare failure reasons and details based on compliance - $failureReasons = if ($anonymousStartDisabled) { - "N/A" - } - else { - "Anonymous users and dial-in callers can start a meeting" + # Prepare failure reasons and details based on compliance + $failureReasons = if ($anonymousStartDisabled) { + "N/A" + } + else { + "Anonymous users and dial-in callers can start a meeting" + } + + $details = "AllowAnonymousUsersToStartMeeting is set to $($CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $anonymousStartDisabled + Status = if ($anonymousStartDisabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "AllowAnonymousUsersToStartMeeting is set to $($CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "8.5.2" - Result = $anonymousStartDisabled - Status = if ($anonymousStartDisabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-NoWhitelistDomains.ps1 b/source/tests/Test-NoWhitelistDomains.ps1 index 820ff7b..92652be 100644 --- a/source/tests/Test-NoWhitelistDomains.ps1 +++ b/source/tests/Test-NoWhitelistDomains.ps1 @@ -9,39 +9,48 @@ function Test-NoWhitelistDomains { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "6.2.2" } process { - # 6.2.2 (L1) Ensure mail transport rules do not whitelist specific domains + try { + # 6.2.2 (L1) Ensure mail transport rules do not whitelist specific domains - # Retrieve transport rules that whitelist specific domains - $whitelistedRules = Get-TransportRule | Where-Object { $_.SetSCL -eq -1 -and $null -ne $_.SenderDomainIs } + # Retrieve transport rules that whitelist specific domains + $whitelistedRules = Get-TransportRule | Where-Object { $_.SetSCL -eq -1 -and $null -ne $_.SenderDomainIs } - # Prepare failure reasons and details based on compliance - $failureReasons = if ($whitelistedRules) { - "There are transport rules whitelisting specific domains." - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($whitelistedRules) { + "There are transport rules whitelisting specific domains." + } + else { + "N/A" + } - $details = if ($whitelistedRules) { - $ruleDetails = $whitelistedRules | ForEach-Object { "{0}: {1}" -f $_.Name, ($_.SenderDomainIs -join ', ') } - "Whitelisted Rules: $($ruleDetails -join '; ')" - } - else { - "No transport rules whitelisting specific domains found." - } + $details = if ($whitelistedRules) { + $ruleDetails = $whitelistedRules | ForEach-Object { "{0}: {1}" -f $_.Name, ($_.SenderDomainIs -join ', ') } + "Whitelisted Rules: $($ruleDetails -join '; ')" + } + else { + "No transport rules whitelisting specific domains found." + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "6.2.2" - Result = -not $whitelistedRules - Status = if ($whitelistedRules) { "Fail" } else { "Pass" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = -not $whitelistedRules + Status = if ($whitelistedRules) { "Fail" } else { "Pass" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-NotifyMalwareInternal.ps1 b/source/tests/Test-NotifyMalwareInternal.ps1 index ba962d6..e09a4b6 100644 --- a/source/tests/Test-NotifyMalwareInternal.ps1 +++ b/source/tests/Test-NotifyMalwareInternal.ps1 @@ -9,9 +9,11 @@ function Test-NotifyMalwareInternal { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "2.1.3" } process { + try { # 2.1.3 Ensure notifications for internal users sending malware is Enabled # Retrieve all 'Custom' malware filter policies and check notification settings @@ -44,7 +46,7 @@ function Test-NotifyMalwareInternal { # Create and populate the CISAuditResult object $params = @{ - Rec = "2.1.3" + Rec = $recnum Result = $result Status = if ($result) { "Pass" } else { "Fail" } Details = $details @@ -52,6 +54,13 @@ function Test-NotifyMalwareInternal { } $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } + } end { # Return the audit result diff --git a/source/tests/Test-OneDriveContentRestrictions.ps1 b/source/tests/Test-OneDriveContentRestrictions.ps1 index 7a69c37..136f951 100644 --- a/source/tests/Test-OneDriveContentRestrictions.ps1 +++ b/source/tests/Test-OneDriveContentRestrictions.ps1 @@ -9,39 +9,48 @@ function Test-OneDriveContentRestrictions { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.2.4" } process { - # 7.2.4 (L2) Ensure OneDrive content sharing is restricted + try { + # 7.2.4 (L2) Ensure OneDrive content sharing is restricted - # Retrieve OneDrive sharing capability settings - $SPOTenant = Get-SPOTenant | Select-Object OneDriveSharingCapability - $isOneDriveSharingRestricted = $SPOTenant.OneDriveSharingCapability -eq 'Disabled' + # Retrieve OneDrive sharing capability settings + $SPOTenant = Get-SPOTenant | Select-Object OneDriveSharingCapability + $isOneDriveSharingRestricted = $SPOTenant.OneDriveSharingCapability -eq 'Disabled' - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $isOneDriveSharingRestricted) { - "OneDrive content sharing is not restricted to 'Disabled'. Current setting: $($SPOTenant.OneDriveSharingCapability)" - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isOneDriveSharingRestricted) { + "OneDrive content sharing is not restricted to 'Disabled'. Current setting: $($SPOTenant.OneDriveSharingCapability)" + } + else { + "N/A" + } - $details = if ($isOneDriveSharingRestricted) { - "OneDrive content sharing is restricted." - } - else { - "OneDriveSharingCapability: $($SPOTenant.OneDriveSharingCapability)" - } + $details = if ($isOneDriveSharingRestricted) { + "OneDrive content sharing is restricted." + } + else { + "OneDriveSharingCapability: $($SPOTenant.OneDriveSharingCapability)" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.2.4" - Result = $isOneDriveSharingRestricted - Status = if ($isOneDriveSharingRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isOneDriveSharingRestricted + Status = if ($isOneDriveSharingRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-OneDriveSyncRestrictions.ps1 b/source/tests/Test-OneDriveSyncRestrictions.ps1 index 5357cda..dbea815 100644 --- a/source/tests/Test-OneDriveSyncRestrictions.ps1 +++ b/source/tests/Test-OneDriveSyncRestrictions.ps1 @@ -9,39 +9,48 @@ function Test-OneDriveSyncRestrictions { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.3.2" } process { - # 7.3.2 (L2) Ensure OneDrive sync is restricted for unmanaged devices + try { + # 7.3.2 (L2) Ensure OneDrive sync is restricted for unmanaged devices - # Retrieve OneDrive sync client restriction settings - $SPOTenantSyncClientRestriction = Get-SPOTenantSyncClientRestriction | Select-Object TenantRestrictionEnabled, AllowedDomainList - $isSyncRestricted = $SPOTenantSyncClientRestriction.TenantRestrictionEnabled -and $SPOTenantSyncClientRestriction.AllowedDomainList + # Retrieve OneDrive sync client restriction settings + $SPOTenantSyncClientRestriction = Get-SPOTenantSyncClientRestriction | Select-Object TenantRestrictionEnabled, AllowedDomainList + $isSyncRestricted = $SPOTenantSyncClientRestriction.TenantRestrictionEnabled -and $SPOTenantSyncClientRestriction.AllowedDomainList - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $isSyncRestricted) { - "OneDrive sync is not restricted to managed devices. TenantRestrictionEnabled should be True and AllowedDomainList should contain trusted domains GUIDs." - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isSyncRestricted) { + "OneDrive sync is not restricted to managed devices. TenantRestrictionEnabled should be True and AllowedDomainList should contain trusted domains GUIDs." + } + else { + "N/A" + } - $details = if ($isSyncRestricted) { - "OneDrive sync is restricted for unmanaged devices." - } - else { - "TenantRestrictionEnabled: $($SPOTenantSyncClientRestriction.TenantRestrictionEnabled); AllowedDomainList: $($SPOTenantSyncClientRestriction.AllowedDomainList -join ', ')" - } + $details = if ($isSyncRestricted) { + "OneDrive sync is restricted for unmanaged devices." + } + else { + "TenantRestrictionEnabled: $($SPOTenantSyncClientRestriction.TenantRestrictionEnabled); AllowedDomainList: $($SPOTenantSyncClientRestriction.AllowedDomainList -join ', ')" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.3.2" - Result = $isSyncRestricted - Status = if ($isSyncRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isSyncRestricted + Status = if ($isSyncRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-OrgOnlyBypassLobby.ps1 b/source/tests/Test-OrgOnlyBypassLobby.ps1 index 7a7e668..1f6a6b3 100644 --- a/source/tests/Test-OrgOnlyBypassLobby.ps1 +++ b/source/tests/Test-OrgOnlyBypassLobby.ps1 @@ -9,41 +9,50 @@ function Test-OrgOnlyBypassLobby { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.5.3" } process { - # 8.5.3 (L1) Ensure only people in my org can bypass the lobby + try { + # 8.5.3 (L1) Ensure only people in my org can bypass the lobby - # Connect to Teams PowerShell using Connect-MicrosoftTeams + # Connect to Teams PowerShell using Connect-MicrosoftTeams - # Retrieve the Teams meeting policy for lobby bypass settings - $CsTeamsMeetingPolicyLobby = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AutoAdmittedUsers - $lobbyBypassRestricted = $CsTeamsMeetingPolicyLobby.AutoAdmittedUsers -eq 'EveryoneInCompanyExcludingGuests' + # Retrieve the Teams meeting policy for lobby bypass settings + $CsTeamsMeetingPolicyLobby = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AutoAdmittedUsers + $lobbyBypassRestricted = $CsTeamsMeetingPolicyLobby.AutoAdmittedUsers -eq 'EveryoneInCompanyExcludingGuests' - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $lobbyBypassRestricted) { - "External participants can bypass the lobby" - } - else { - "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $lobbyBypassRestricted) { + "External participants can bypass the lobby" + } + else { + "N/A" + } - $details = if ($lobbyBypassRestricted) { - "Only people in the organization can bypass the lobby." - } - else { - "AutoAdmittedUsers is set to $($CsTeamsMeetingPolicyLobby.AutoAdmittedUsers)" - } + $details = if ($lobbyBypassRestricted) { + "Only people in the organization can bypass the lobby." + } + else { + "AutoAdmittedUsers is set to $($CsTeamsMeetingPolicyLobby.AutoAdmittedUsers)" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "8.5.3" - Result = $lobbyBypassRestricted - Status = if ($lobbyBypassRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $lobbyBypassRestricted + Status = if ($lobbyBypassRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-OrganizersPresent.ps1 b/source/tests/Test-OrganizersPresent.ps1 index 337e671..e0215f5 100644 --- a/source/tests/Test-OrganizersPresent.ps1 +++ b/source/tests/Test-OrganizersPresent.ps1 @@ -9,9 +9,11 @@ function Test-OrganizersPresent { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.5.6" } process { + try { # 8.5.6 (L2) Ensure only organizers and co-organizers can present # Connect to Teams PowerShell using Connect-MicrosoftTeams @@ -37,7 +39,7 @@ function Test-OrganizersPresent { # Create and populate the CISAuditResult object $params = @{ - Rec = "8.5.6" + Rec = $recnum Result = $presenterRoleRestricted Status = if ($presenterRoleRestricted) { "Pass" } else { "Fail" } Details = $details @@ -45,6 +47,13 @@ function Test-OrganizersPresent { } $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } + } end { # Return the audit result diff --git a/source/tests/Test-PasswordHashSync.ps1 b/source/tests/Test-PasswordHashSync.ps1 index 583d65e..42afa1c 100644 --- a/source/tests/Test-PasswordHashSync.ps1 +++ b/source/tests/Test-PasswordHashSync.ps1 @@ -9,9 +9,11 @@ function Test-PasswordHashSync { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "5.1.8.1" } process { + try { # 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments # Pass if OnPremisesSyncEnabled is True. Fail otherwise. @@ -31,7 +33,7 @@ function Test-PasswordHashSync { # Create and populate the CISAuditResult object $params = @{ - Rec = "5.1.8.1" + Rec = $recnum Result = $hashSyncResult Status = if ($hashSyncResult) { "Pass" } else { "Fail" } Details = $details @@ -39,6 +41,13 @@ function Test-PasswordHashSync { } $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } + } end { # Return the audit result diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index 530d481..63f2166 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -10,34 +10,43 @@ function Test-PasswordNeverExpirePolicy { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "1.3.1" } process { - # 1.3.1 (L1) Ensure the 'Password expiration policy' is set to 'Set passwords to never expire' - # Pass if PasswordValidityPeriodInDays is 0. Fail otherwise. + 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 + # 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" + # Prepare failure reasons and details based on compliance + $failureReasons = if ($passwordPolicy -ne 0) { + "Password expiration is not set to never expire" + } + else { + "N/A" + } + + $details = "Validity Period: $passwordPolicy days" + + # 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 + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "Validity Period: $passwordPolicy days" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "1.3.1" - Result = $passwordPolicy -eq 0 - Status = if ($passwordPolicy -eq 0) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-ReauthWithCode.ps1 b/source/tests/Test-ReauthWithCode.ps1 index 28ac0f0..5274b46 100644 --- a/source/tests/Test-ReauthWithCode.ps1 +++ b/source/tests/Test-ReauthWithCode.ps1 @@ -9,34 +9,43 @@ function Test-ReauthWithCode { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.2.10" } process { - # 7.2.10 (L1) Ensure reauthentication with verification code is restricted + try { + # 7.2.10 (L1) Ensure reauthentication with verification code is restricted - # Retrieve reauthentication settings for SharePoint Online - $SPOTenantReauthentication = Get-SPOTenant | Select-Object EmailAttestationRequired, EmailAttestationReAuthDays - $isReauthenticationRestricted = $SPOTenantReauthentication.EmailAttestationRequired -and $SPOTenantReauthentication.EmailAttestationReAuthDays -le 15 + # Retrieve reauthentication settings for SharePoint Online + $SPOTenantReauthentication = Get-SPOTenant | Select-Object EmailAttestationRequired, EmailAttestationReAuthDays + $isReauthenticationRestricted = $SPOTenantReauthentication.EmailAttestationRequired -and $SPOTenantReauthentication.EmailAttestationReAuthDays -le 15 - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $isReauthenticationRestricted) { - "Reauthentication with verification code does not require reauthentication within 15 days or less." - } - else { - "N/A" + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isReauthenticationRestricted) { + "Reauthentication with verification code does not require reauthentication within 15 days or less." + } + else { + "N/A" + } + + $details = "EmailAttestationRequired: $($SPOTenantReauthentication.EmailAttestationRequired); EmailAttestationReAuthDays: $($SPOTenantReauthentication.EmailAttestationReAuthDays)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isReauthenticationRestricted + Status = if ($isReauthenticationRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "EmailAttestationRequired: $($SPOTenantReauthentication.EmailAttestationRequired); EmailAttestationReAuthDays: $($SPOTenantReauthentication.EmailAttestationReAuthDays)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.2.10" - Result = $isReauthenticationRestricted - Status = if ($isReauthenticationRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-ReportSecurityInTeams.ps1 b/source/tests/Test-ReportSecurityInTeams.ps1 index f79cf17..cc9c205 100644 --- a/source/tests/Test-ReportSecurityInTeams.ps1 +++ b/source/tests/Test-ReportSecurityInTeams.ps1 @@ -9,44 +9,53 @@ function Test-ReportSecurityInTeams { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "8.6.1" } process { - # 8.6.1 (L1) Ensure users can report security concerns in Teams + try { + # 8.6.1 (L1) Ensure users can report security concerns in Teams - # Retrieve the necessary settings for Teams and Exchange Online - $CsTeamsMessagingPolicy = Get-CsTeamsMessagingPolicy -Identity Global | Select-Object -Property AllowSecurityEndUserReporting - $ReportSubmissionPolicy = Get-ReportSubmissionPolicy | Select-Object -Property ReportJunkToCustomizedAddress, ReportNotJunkToCustomizedAddress, ReportPhishToCustomizedAddress, ReportChatMessageToCustomizedAddressEnabled + # Retrieve the necessary settings for Teams and Exchange Online + $CsTeamsMessagingPolicy = Get-CsTeamsMessagingPolicy -Identity Global | Select-Object -Property AllowSecurityEndUserReporting + $ReportSubmissionPolicy = Get-ReportSubmissionPolicy | Select-Object -Property ReportJunkToCustomizedAddress, ReportNotJunkToCustomizedAddress, ReportPhishToCustomizedAddress, ReportChatMessageToCustomizedAddressEnabled - $securityReportEnabled = $CsTeamsMessagingPolicy.AllowSecurityEndUserReporting -and - $ReportSubmissionPolicy.ReportJunkToCustomizedAddress -and - $ReportSubmissionPolicy.ReportNotJunkToCustomizedAddress -and - $ReportSubmissionPolicy.ReportPhishToCustomizedAddress -and - $ReportSubmissionPolicy.ReportChatMessageToCustomizedAddressEnabled + $securityReportEnabled = $CsTeamsMessagingPolicy.AllowSecurityEndUserReporting -and + $ReportSubmissionPolicy.ReportJunkToCustomizedAddress -and + $ReportSubmissionPolicy.ReportNotJunkToCustomizedAddress -and + $ReportSubmissionPolicy.ReportPhishToCustomizedAddress -and + $ReportSubmissionPolicy.ReportChatMessageToCustomizedAddressEnabled - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $securityReportEnabled) { - "Users cannot report security concerns in Teams due to one or more incorrect settings" - } - else { - "N/A" + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $securityReportEnabled) { + "Users cannot report security concerns in Teams due to one or more incorrect settings" + } + else { + "N/A" + } + + $details = "AllowSecurityEndUserReporting: $($CsTeamsMessagingPolicy.AllowSecurityEndUserReporting); " + + "ReportJunkToCustomizedAddress: $($ReportSubmissionPolicy.ReportJunkToCustomizedAddress); " + + "ReportNotJunkToCustomizedAddress: $($ReportSubmissionPolicy.ReportNotJunkToCustomizedAddress); " + + "ReportPhishToCustomizedAddress: $($ReportSubmissionPolicy.ReportPhishToCustomizedAddress); " + + "ReportChatMessageToCustomizedAddressEnabled: $($ReportSubmissionPolicy.ReportChatMessageToCustomizedAddressEnabled)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $securityReportEnabled + Status = if ($securityReportEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "AllowSecurityEndUserReporting: $($CsTeamsMessagingPolicy.AllowSecurityEndUserReporting); " + - "ReportJunkToCustomizedAddress: $($ReportSubmissionPolicy.ReportJunkToCustomizedAddress); " + - "ReportNotJunkToCustomizedAddress: $($ReportSubmissionPolicy.ReportNotJunkToCustomizedAddress); " + - "ReportPhishToCustomizedAddress: $($ReportSubmissionPolicy.ReportPhishToCustomizedAddress); " + - "ReportChatMessageToCustomizedAddressEnabled: $($ReportSubmissionPolicy.ReportChatMessageToCustomizedAddressEnabled)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "8.6.1" - Result = $securityReportEnabled - Status = if ($securityReportEnabled) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 43a8eef..cc3c051 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -9,49 +9,58 @@ function Test-RestrictCustomScripts { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.3.4" } process { - # 7.3.4 (L1) Ensure custom script execution is restricted on site collections + try { + # 7.3.4 (L1) Ensure custom script execution is restricted on site collections - # Retrieve all site collections and select necessary properties - $SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages + # Retrieve all site collections and select necessary properties + $SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages - # Find sites where custom scripts are allowed (DenyAddAndCustomizePages is not 'Enabled') - $customScriptAllowedSites = $SPOSitesCustomScript | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } + # Find sites where custom scripts are allowed (DenyAddAndCustomizePages is not 'Enabled') + $customScriptAllowedSites = $SPOSitesCustomScript | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } - # Compliance is true if no sites allow custom scripts - $complianceResult = $customScriptAllowedSites.Count -eq 0 + # Compliance is true if no sites allow custom scripts + $complianceResult = $customScriptAllowedSites.Count -eq 0 - # Gather details for non-compliant sites (where custom scripts are allowed) - $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { - "$($_.Title) ($($_.Url)): Custom Script Allowed" + # Gather details for non-compliant sites (where custom scripts are allowed) + $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { + "$($_.Title) ($($_.Url)): Custom Script Allowed" + } + + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $complianceResult) { + "The following site collections allow custom script execution: " + ($nonCompliantSiteDetails -join "; ") + } + else { + "N/A" + } + + $details = if ($complianceResult) { + "All site collections have custom script execution restricted" + } + else { + $nonCompliantSiteDetails -join "; " + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $complianceResult + Status = if ($complianceResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $complianceResult) { - "The following site collections allow custom script execution: " + ($nonCompliantSiteDetails -join "; ") + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - else { - "N/A" - } - - $details = if ($complianceResult) { - "All site collections have custom script execution restricted" - } - else { - $nonCompliantSiteDetails -join "; " - } - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.3.4" - Result = $complianceResult - Status = if ($complianceResult) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-RestrictExternalSharing.ps1 b/source/tests/Test-RestrictExternalSharing.ps1 index f1b0568..a974262 100644 --- a/source/tests/Test-RestrictExternalSharing.ps1 +++ b/source/tests/Test-RestrictExternalSharing.ps1 @@ -9,34 +9,43 @@ function Test-RestrictExternalSharing { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "7.2.3" } process { - # 7.2.3 (L1) Ensure external content sharing is restricted + try { + # 7.2.3 (L1) Ensure external content sharing is restricted - # Retrieve the SharingCapability setting for the SharePoint tenant - $SPOTenantSharingCapability = Get-SPOTenant | Select-Object SharingCapability - $isRestricted = $SPOTenantSharingCapability.SharingCapability -in @('ExternalUserSharingOnly', 'ExistingExternalUserSharingOnly', 'Disabled') + # Retrieve the SharingCapability setting for the SharePoint tenant + $SPOTenantSharingCapability = Get-SPOTenant | Select-Object SharingCapability + $isRestricted = $SPOTenantSharingCapability.SharingCapability -in @('ExternalUserSharingOnly', 'ExistingExternalUserSharingOnly', 'Disabled') - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $isRestricted) { - "External content sharing is not adequately restricted. Current setting: $($SPOTenantSharingCapability.SharingCapability)" - } - else { - "N/A" + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isRestricted) { + "External content sharing is not adequately restricted. Current setting: $($SPOTenantSharingCapability.SharingCapability)" + } + else { + "N/A" + } + + $details = "SharingCapability: $($SPOTenantSharingCapability.SharingCapability)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isRestricted + Status = if ($isRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "SharingCapability: $($SPOTenantSharingCapability.SharingCapability)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "7.2.3" - Result = $isRestricted - Status = if ($isRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-RestrictOutlookAddins.ps1 b/source/tests/Test-RestrictOutlookAddins.ps1 index 4438b50..1cbcf34 100644 --- a/source/tests/Test-RestrictOutlookAddins.ps1 +++ b/source/tests/Test-RestrictOutlookAddins.ps1 @@ -12,63 +12,72 @@ function Test-RestrictOutlookAddins { $customPolicyFailures = @() $defaultPolicyFailureDetails = @() $relevantRoles = @('My Custom Apps', 'My Marketplace Apps', 'My ReadWriteMailbox Apps') + $recnum = "6.3.1" } process { - # 6.3.1 (L2) Ensure users installing Outlook add-ins is not allowed + try { + # 6.3.1 (L2) Ensure users installing Outlook add-ins is not allowed - # Check all mailboxes for custom policies with unallowed add-ins - $roleAssignmentPolicies = Get-EXOMailbox | Select-Object -Unique RoleAssignmentPolicy + # Check all mailboxes for custom policies with unallowed add-ins + $roleAssignmentPolicies = Get-EXOMailbox | Select-Object -Unique RoleAssignmentPolicy - if ($roleAssignmentPolicies.RoleAssignmentPolicy) { - foreach ($policy in $roleAssignmentPolicies) { - if ($policy.RoleAssignmentPolicy) { - $rolePolicyDetails = Get-RoleAssignmentPolicy -Identity $policy.RoleAssignmentPolicy - $foundRoles = $rolePolicyDetails.AssignedRoles | Where-Object { $_ -in $relevantRoles } - if ($foundRoles) { - $customPolicyFailures += "Policy: $($policy.RoleAssignmentPolicy): Roles: $($foundRoles -join ', ')" + if ($roleAssignmentPolicies.RoleAssignmentPolicy) { + foreach ($policy in $roleAssignmentPolicies) { + if ($policy.RoleAssignmentPolicy) { + $rolePolicyDetails = Get-RoleAssignmentPolicy -Identity $policy.RoleAssignmentPolicy + $foundRoles = $rolePolicyDetails.AssignedRoles | Where-Object { $_ -in $relevantRoles } + if ($foundRoles) { + $customPolicyFailures += "Policy: $($policy.RoleAssignmentPolicy): Roles: $($foundRoles -join ', ')" + } } } } - } - # Check Default Role Assignment Policy - $defaultPolicy = Get-RoleAssignmentPolicy "Default Role Assignment Policy" - $defaultPolicyRoles = $defaultPolicy.AssignedRoles | Where-Object { $_ -in $relevantRoles } - if ($defaultPolicyRoles) { - $defaultPolicyFailureDetails = $defaultPolicyRoles - } + # Check Default Role Assignment Policy + $defaultPolicy = Get-RoleAssignmentPolicy "Default Role Assignment Policy" + $defaultPolicyRoles = $defaultPolicy.AssignedRoles | Where-Object { $_ -in $relevantRoles } + if ($defaultPolicyRoles) { + $defaultPolicyFailureDetails = $defaultPolicyRoles + } - # Prepare result details string - $detailsString = "" - if ($customPolicyFailures) { - $detailsString += "Custom Policy Failures: | " - $detailsString += ($customPolicyFailures -join " | ") - } - else { - $detailsString += "Custom Policy Failures: None | " - } + # Prepare result details string + $detailsString = "" + if ($customPolicyFailures) { + $detailsString += "Custom Policy Failures: | " + $detailsString += ($customPolicyFailures -join " | ") + } + else { + $detailsString += "Custom Policy Failures: None | " + } - $detailsString += "Default Role Assignment Policy: " - if ($defaultPolicyFailureDetails) { - $detailsString += ($defaultPolicyFailureDetails -join ', ') - } - else { - $detailsString += "Compliant" - } + $detailsString += "Default Role Assignment Policy: " + if ($defaultPolicyFailureDetails) { + $detailsString += ($defaultPolicyFailureDetails -join ', ') + } + else { + $detailsString += "Compliant" + } - # Determine result based on findings - $isCompliant = -not ($customPolicyFailures -or $defaultPolicyFailureDetails) + # Determine result based on findings + $isCompliant = -not ($customPolicyFailures -or $defaultPolicyFailureDetails) - # Create and populate the CISAuditResult object - $params = @{ - Rec = "6.3.1" - Result = $isCompliant - Status = if ($isCompliant) { "Pass" } else { "Fail" } - Details = $detailsString - FailureReason = if ($isCompliant) { "N/A" } else { "Unauthorized Outlook add-ins found in custom or default policies." } + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $isCompliant + Status = if ($isCompliant) { "Pass" } else { "Fail" } + Details = $detailsString + FailureReason = if ($isCompliant) { "N/A" } else { "Unauthorized Outlook add-ins found in custom or default policies." } + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 index 8400d72..453b367 100644 --- a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 +++ b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 @@ -9,9 +9,11 @@ function Test-RestrictStorageProvidersOutlook { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "6.5.3" } process { + try { # 6.5.3 (L2) Ensure additional storage providers are restricted in Outlook on the web # Retrieve all OwaMailbox policies @@ -38,7 +40,7 @@ function Test-RestrictStorageProvidersOutlook { # Create and populate the CISAuditResult object $params = @{ - Rec = "6.5.3" + Rec = $recnum Result = $allPoliciesRestricted Status = if ($allPoliciesRestricted) { "Pass" } else { "Fail" } Details = $details @@ -46,6 +48,13 @@ function Test-RestrictStorageProvidersOutlook { } $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } + } end { # Return the audit result diff --git a/source/tests/Test-RestrictTenantCreation.ps1 b/source/tests/Test-RestrictTenantCreation.ps1 index 96bfb0f..36107ae 100644 --- a/source/tests/Test-RestrictTenantCreation.ps1 +++ b/source/tests/Test-RestrictTenantCreation.ps1 @@ -9,34 +9,43 @@ function Test-RestrictTenantCreation { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "5.1.2.3" } process { - # 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes' + try { + # 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes' - # Retrieve the tenant creation policy - $tenantCreationPolicy = (Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions | Select-Object AllowedToCreateTenants - $tenantCreationResult = -not $tenantCreationPolicy.AllowedToCreateTenants + # Retrieve the tenant creation policy + $tenantCreationPolicy = (Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions | Select-Object AllowedToCreateTenants + $tenantCreationResult = -not $tenantCreationPolicy.AllowedToCreateTenants - # Prepare failure reasons and details based on compliance - $failureReasons = if ($tenantCreationResult) { - "N/A" - } - else { - "Non-admin users can create tenants" + # Prepare failure reasons and details based on compliance + $failureReasons = if ($tenantCreationResult) { + "N/A" + } + else { + "Non-admin users can create tenants" + } + + $details = "AllowedToCreateTenants: $($tenantCreationPolicy.AllowedToCreateTenants)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $tenantCreationResult + Status = if ($tenantCreationResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = "AllowedToCreateTenants: $($tenantCreationPolicy.AllowedToCreateTenants)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = "5.1.2.3" - Result = $tenantCreationResult - Status = if ($tenantCreationResult) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SafeAttachmentsPolicy.ps1 b/source/tests/Test-SafeAttachmentsPolicy.ps1 index 48597ce..eafc7ff 100644 --- a/source/tests/Test-SafeAttachmentsPolicy.ps1 +++ b/source/tests/Test-SafeAttachmentsPolicy.ps1 @@ -9,39 +9,48 @@ function Test-SafeAttachmentsPolicy { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "2.1.4" } process { - # 2.1.4 (L2) Ensure Safe Attachments policy is enabled + try { + # 2.1.4 (L2) Ensure Safe Attachments policy is enabled - # Retrieve all Safe Attachment policies where Enable is set to True - $safeAttachmentPolicies = Get-SafeAttachmentPolicy | Where-Object { $_.Enable -eq $true } + # Retrieve all Safe Attachment policies where Enable is set to True + $safeAttachmentPolicies = Get-SafeAttachmentPolicy | Where-Object { $_.Enable -eq $true } - # Determine result and details based on the presence of enabled policies - $result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0 - $details = if ($result) { - "Enabled Safe Attachments Policies: $($safeAttachmentPolicies.Name -join ', ')" - } - else { - "No Safe Attachments Policies are enabled." - } + # Determine result and details based on the presence of enabled policies + $result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0 + $details = if ($result) { + "Enabled Safe Attachments Policies: $($safeAttachmentPolicies.Name -join ', ')" + } + else { + "No Safe Attachments Policies are enabled." + } - $failureReasons = if ($result) { - "N/A" - } - else { - "Safe Attachments policy is not enabled." - } + $failureReasons = if ($result) { + "N/A" + } + else { + "Safe Attachments policy is not enabled." + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "2.1.4" - Result = $result - Status = if ($result) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SafeAttachmentsTeams.ps1 b/source/tests/Test-SafeAttachmentsTeams.ps1 index a1cb453..1d9e32b 100644 --- a/source/tests/Test-SafeAttachmentsTeams.ps1 +++ b/source/tests/Test-SafeAttachmentsTeams.ps1 @@ -9,46 +9,55 @@ function Test-SafeAttachmentsTeams { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "2.1.5" } process { - # 2.1.5 (L2) Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled + try { + # 2.1.5 (L2) Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled - # Retrieve the ATP policies for Office 365 and check Safe Attachments settings - $atpPolicies = Get-AtpPolicyForO365 + # Retrieve the ATP policies for Office 365 and check Safe Attachments settings + $atpPolicies = Get-AtpPolicyForO365 - # Check if the required ATP policies are enabled - $atpPolicyResult = $atpPolicies | Where-Object { - $_.EnableATPForSPOTeamsODB -eq $true -and - $_.EnableSafeDocs -eq $true -and - $_.AllowSafeDocsOpen -eq $false - } + # Check if the required ATP policies are enabled + $atpPolicyResult = $atpPolicies | Where-Object { + $_.EnableATPForSPOTeamsODB -eq $true -and + $_.EnableSafeDocs -eq $true -and + $_.AllowSafeDocsOpen -eq $false + } - # Determine the result based on the ATP policy settings - $result = $null -ne $atpPolicyResult - $details = if ($result) { - "ATP for SharePoint, OneDrive, and Teams is enabled with correct settings." - } - else { - "ATP for SharePoint, OneDrive, and Teams is not enabled with correct settings." - } + # Determine the result based on the ATP policy settings + $result = $null -ne $atpPolicyResult + $details = if ($result) { + "ATP for SharePoint, OneDrive, and Teams is enabled with correct settings." + } + else { + "ATP for SharePoint, OneDrive, and Teams is not enabled with correct settings." + } - $failureReasons = if ($result) { - "N/A" - } - else { - "ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured." - } + $failureReasons = if ($result) { + "N/A" + } + else { + "ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured." + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "2.1.5" - Result = $result - Status = if ($result) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SafeLinksOfficeApps.ps1 b/source/tests/Test-SafeLinksOfficeApps.ps1 index 46ee852..0660da2 100644 --- a/source/tests/Test-SafeLinksOfficeApps.ps1 +++ b/source/tests/Test-SafeLinksOfficeApps.ps1 @@ -9,53 +9,62 @@ function Test-SafeLinksOfficeApps { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "2.1.1" } process { - # 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled + try { + # 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled - # Retrieve all Safe Links policies - $policies = Get-SafeLinksPolicy + # Retrieve all Safe Links policies + $policies = Get-SafeLinksPolicy - # Initialize the details collection - $misconfiguredDetails = @() + # Initialize the details collection + $misconfiguredDetails = @() - foreach ($policy in $policies) { - # Get the detailed configuration of each policy - $policyDetails = Get-SafeLinksPolicy -Identity $policy.Name + foreach ($policy in $policies) { + # Get the detailed configuration of each policy + $policyDetails = Get-SafeLinksPolicy -Identity $policy.Name - # Check each required property and record failures - $failures = @() - if ($policyDetails.EnableSafeLinksForEmail -ne $true) { $failures += "EnableSafeLinksForEmail: False" } - if ($policyDetails.EnableSafeLinksForTeams -ne $true) { $failures += "EnableSafeLinksForTeams: False" } - if ($policyDetails.EnableSafeLinksForOffice -ne $true) { $failures += "EnableSafeLinksForOffice: False" } - if ($policyDetails.TrackClicks -ne $true) { $failures += "TrackClicks: False" } - if ($policyDetails.AllowClickThrough -ne $false) { $failures += "AllowClickThrough: True" } - if ($policyDetails.ScanUrls -ne $true) { $failures += "ScanUrls: False" } - if ($policyDetails.EnableForInternalSenders -ne $true) { $failures += "EnableForInternalSenders: False" } - if ($policyDetails.DeliverMessageAfterScan -ne $true) { $failures += "DeliverMessageAfterScan: False" } - if ($policyDetails.DisableUrlRewrite -ne $false) { $failures += "DisableUrlRewrite: True" } + # Check each required property and record failures + $failures = @() + if ($policyDetails.EnableSafeLinksForEmail -ne $true) { $failures += "EnableSafeLinksForEmail: False" } + if ($policyDetails.EnableSafeLinksForTeams -ne $true) { $failures += "EnableSafeLinksForTeams: False" } + if ($policyDetails.EnableSafeLinksForOffice -ne $true) { $failures += "EnableSafeLinksForOffice: False" } + if ($policyDetails.TrackClicks -ne $true) { $failures += "TrackClicks: False" } + if ($policyDetails.AllowClickThrough -ne $false) { $failures += "AllowClickThrough: True" } + if ($policyDetails.ScanUrls -ne $true) { $failures += "ScanUrls: False" } + if ($policyDetails.EnableForInternalSenders -ne $true) { $failures += "EnableForInternalSenders: False" } + if ($policyDetails.DeliverMessageAfterScan -ne $true) { $failures += "DeliverMessageAfterScan: False" } + if ($policyDetails.DisableUrlRewrite -ne $false) { $failures += "DisableUrlRewrite: True" } - # Only add details for policies that have misconfigurations - if ($failures.Count -gt 0) { - $misconfiguredDetails += "Policy: $($policy.Name); Failures: $($failures -join ', ')" + # Only add details for policies that have misconfigurations + if ($failures.Count -gt 0) { + $misconfiguredDetails += "Policy: $($policy.Name); Failures: $($failures -join ', ')" + } } - } - # Prepare the final result - $result = $misconfiguredDetails.Count -eq 0 - $details = if ($result) { "All Safe Links policies are correctly configured." } else { $misconfiguredDetails -join ' | ' } - $failureReasons = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" } + # Prepare the final result + $result = $misconfiguredDetails.Count -eq 0 + $details = if ($result) { "All Safe Links policies are correctly configured." } else { $misconfiguredDetails -join ' | ' } + $failureReasons = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" } - # Create and populate the CISAuditResult object - $params = @{ - Rec = "2.1.1" - Result = $result - Status = if ($result) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SharePointAADB2B.ps1 b/source/tests/Test-SharePointAADB2B.ps1 index a9af0c4..7f1b6fb 100644 --- a/source/tests/Test-SharePointAADB2B.ps1 +++ b/source/tests/Test-SharePointAADB2B.ps1 @@ -11,21 +11,30 @@ function Test-SharePointAADB2B { # Initialization code, if needed $auditResult = [CISAuditResult]::new() + $recnum = "7.2.2" } process { - # 7.2.2 (L1) Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled - $SPOTenantAzureADB2B = Get-SPOTenant | Select-Object EnableAzureADB2BIntegration + try { + # 7.2.2 (L1) Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled + $SPOTenantAzureADB2B = Get-SPOTenant | Select-Object EnableAzureADB2BIntegration - # Populate the auditResult object with the required properties - $params = @{ - Rec = "7.2.2" - Result = $SPOTenantAzureADB2B.EnableAzureADB2BIntegration - Status = if ($SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Pass" } else { "Fail" } - Details = "EnableAzureADB2BIntegration: $($SPOTenantAzureADB2B.EnableAzureADB2BIntegration)" - FailureReason = if (-not $SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Azure AD B2B integration is not enabled" } else { "N/A" } + # Populate the auditResult object with the required properties + $params = @{ + Rec = $recnum + Result = $SPOTenantAzureADB2B.EnableAzureADB2BIntegration + Status = if ($SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Pass" } else { "Fail" } + Details = "EnableAzureADB2BIntegration: $($SPOTenantAzureADB2B.EnableAzureADB2BIntegration)" + FailureReason = if (-not $SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Azure AD B2B integration is not enabled" } else { "N/A" } + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SharePointExternalSharingDomains.ps1 b/source/tests/Test-SharePointExternalSharingDomains.ps1 index 25f4213..f828ccf 100644 --- a/source/tests/Test-SharePointExternalSharingDomains.ps1 +++ b/source/tests/Test-SharePointExternalSharingDomains.ps1 @@ -11,22 +11,31 @@ function Test-SharePointExternalSharingDomains { # Initialization code, if needed $auditResult = [CISAuditResult]::new() + $recnum = "7.2.6" } process { - # 7.2.6 (L2) Ensure SharePoint external sharing is managed through domain whitelist/blacklists - $SPOTenant = Get-SPOTenant | Select-Object SharingDomainRestrictionMode, SharingAllowedDomainList - $isDomainRestrictionConfigured = $SPOTenant.SharingDomainRestrictionMode -eq 'AllowList' + try { + # 7.2.6 (L2) Ensure SharePoint external sharing is managed through domain whitelist/blacklists + $SPOTenant = Get-SPOTenant | Select-Object SharingDomainRestrictionMode, SharingAllowedDomainList + $isDomainRestrictionConfigured = $SPOTenant.SharingDomainRestrictionMode -eq 'AllowList' - # Populate the auditResult object with the required properties - $params = @{ - Rec = "7.2.6" - Result = $isDomainRestrictionConfigured - Status = if ($isDomainRestrictionConfigured) { "Pass" } else { "Fail" } - Details = "SharingDomainRestrictionMode: $($SPOTenant.SharingDomainRestrictionMode); SharingAllowedDomainList: $($SPOTenant.SharingAllowedDomainList)" - FailureReason = if (-not $isDomainRestrictionConfigured) { "Domain restrictions for SharePoint external sharing are not configured to 'AllowList'. Current setting: $($SPOTenant.SharingDomainRestrictionMode)" } else { "N/A" } + # Populate the auditResult object with the required properties + $params = @{ + Rec = $recnum + Result = $isDomainRestrictionConfigured + Status = if ($isDomainRestrictionConfigured) { "Pass" } else { "Fail" } + Details = "SharingDomainRestrictionMode: $($SPOTenant.SharingDomainRestrictionMode); SharingAllowedDomainList: $($SPOTenant.SharingAllowedDomainList)" + FailureReason = if (-not $isDomainRestrictionConfigured) { "Domain restrictions for SharePoint external sharing are not configured to 'AllowList'. Current setting: $($SPOTenant.SharingDomainRestrictionMode)" } else { "N/A" } + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SharePointGuestsItemSharing.ps1 b/source/tests/Test-SharePointGuestsItemSharing.ps1 index 6f35325..025951f 100644 --- a/source/tests/Test-SharePointGuestsItemSharing.ps1 +++ b/source/tests/Test-SharePointGuestsItemSharing.ps1 @@ -11,22 +11,31 @@ function Test-SharePointGuestsItemSharing { # Initialization code, if needed $auditResult = [CISAuditResult]::new() + $recnum = "7.2.5" } process { - # 7.2.5 (L2) Ensure that SharePoint guest users cannot share items they don't own - $SPOTenant = Get-SPOTenant | Select-Object PreventExternalUsersFromResharing - $isGuestResharingPrevented = $SPOTenant.PreventExternalUsersFromResharing + try { + # 7.2.5 (L2) Ensure that SharePoint guest users cannot share items they don't own + $SPOTenant = Get-SPOTenant | Select-Object PreventExternalUsersFromResharing + $isGuestResharingPrevented = $SPOTenant.PreventExternalUsersFromResharing - # Populate the auditResult object with the required properties - $params = @{ - Rec = "7.2.5" - Result = $isGuestResharingPrevented - Status = if ($isGuestResharingPrevented) { "Pass" } else { "Fail" } - Details = "PreventExternalUsersFromResharing: $isGuestResharingPrevented" - FailureReason = if (-not $isGuestResharingPrevented) { "Guest users can reshare items they don't own." } else { "N/A" } + # Populate the auditResult object with the required properties + $params = @{ + Rec = $recnum + Result = $isGuestResharingPrevented + Status = if ($isGuestResharingPrevented) { "Pass" } else { "Fail" } + Details = "PreventExternalUsersFromResharing: $isGuestResharingPrevented" + FailureReason = if (-not $isGuestResharingPrevented) { "Guest users can reshare items they don't own." } else { "N/A" } + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SpamPolicyAdminNotify.ps1 b/source/tests/Test-SpamPolicyAdminNotify.ps1 index 05be9aa..aa2b181 100644 --- a/source/tests/Test-SpamPolicyAdminNotify.ps1 +++ b/source/tests/Test-SpamPolicyAdminNotify.ps1 @@ -11,37 +11,46 @@ function Test-SpamPolicyAdminNotify { # Initialization code, if needed $auditResult = [CISAuditResult]::new() + $recnum = "2.1.6" } process { - # 2.1.6 Ensure Exchange Online Spam Policies are set to notify administrators + try { + # 2.1.6 Ensure Exchange Online Spam Policies are set to notify administrators - # Get the default hosted outbound spam filter policy - $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy | Where-Object { $_.IsDefault -eq $true } + # Get the default hosted outbound spam filter policy + $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy | Where-Object { $_.IsDefault -eq $true } - # Check if both settings are enabled - $bccSuspiciousOutboundMailEnabled = $hostedOutboundSpamFilterPolicy.BccSuspiciousOutboundMail - $notifyOutboundSpamEnabled = $hostedOutboundSpamFilterPolicy.NotifyOutboundSpam - $areSettingsEnabled = $bccSuspiciousOutboundMailEnabled -and $notifyOutboundSpamEnabled + # Check if both settings are enabled + $bccSuspiciousOutboundMailEnabled = $hostedOutboundSpamFilterPolicy.BccSuspiciousOutboundMail + $notifyOutboundSpamEnabled = $hostedOutboundSpamFilterPolicy.NotifyOutboundSpam + $areSettingsEnabled = $bccSuspiciousOutboundMailEnabled -and $notifyOutboundSpamEnabled - # Prepare failure details if any setting is not enabled - $failureDetails = @() - if (-not $bccSuspiciousOutboundMailEnabled) { - $failureDetails += "BccSuspiciousOutboundMail is not enabled." - } - if (-not $notifyOutboundSpamEnabled) { - $failureDetails += "NotifyOutboundSpam is not enabled." + # Prepare failure details if any setting is not enabled + $failureDetails = @() + if (-not $bccSuspiciousOutboundMailEnabled) { + $failureDetails += "BccSuspiciousOutboundMail is not enabled." + } + if (-not $notifyOutboundSpamEnabled) { + $failureDetails += "NotifyOutboundSpam is not enabled." + } + + # Create an instance of CISAuditResult and populate it + $params = @{ + Rec = $recnum + Result = $areSettingsEnabled + Status = if ($areSettingsEnabled) { "Pass" } else { "Fail" } + Details = if ($areSettingsEnabled) { "Both BccSuspiciousOutboundMail and NotifyOutboundSpam are enabled." } else { $failureDetails -join ' ' } + FailureReason = if (-not $areSettingsEnabled) { "One or both spam policies are not set to notify administrators." } else { "N/A" } + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - # Create an instance of CISAuditResult and populate it - $params = @{ - Rec = "2.1.6" - Result = $areSettingsEnabled - Status = if ($areSettingsEnabled) { "Pass" } else { "Fail" } - Details = if ($areSettingsEnabled) { "Both BccSuspiciousOutboundMail and NotifyOutboundSpam are enabled." } else { $failureDetails -join ' ' } - FailureReason = if (-not $areSettingsEnabled) { "One or both spam policies are not set to notify administrators." } else { "N/A" } + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-TeamsExternalAccess.ps1 b/source/tests/Test-TeamsExternalAccess.ps1 index 8b0cad2..c4ee735 100644 --- a/source/tests/Test-TeamsExternalAccess.ps1 +++ b/source/tests/Test-TeamsExternalAccess.ps1 @@ -11,32 +11,41 @@ function Test-TeamsExternalAccess { # Initialization code, if needed $auditResult = [CISAuditResult]::new() + $recnum = "8.2.1" } process { - # 8.2.1 (L1) Ensure 'external access' is restricted in the Teams admin center + try { + # 8.2.1 (L1) Ensure 'external access' is restricted in the Teams admin center - # Connect to Teams PowerShell using Connect-MicrosoftTeams + # Connect to Teams PowerShell using Connect-MicrosoftTeams - $externalAccessConfig = Get-CsTenantFederationConfiguration + $externalAccessConfig = Get-CsTenantFederationConfiguration - $allowedDomainsLimited = $false - if ($externalAccessConfig.AllowFederatedUsers -and $externalAccessConfig.AllowedDomains -and $externalAccessConfig.AllowedDomains.AllowedDomain.Count -gt 0) { - $allowedDomainsLimited = $true + $allowedDomainsLimited = $false + if ($externalAccessConfig.AllowFederatedUsers -and $externalAccessConfig.AllowedDomains -and $externalAccessConfig.AllowedDomains.AllowedDomain.Count -gt 0) { + $allowedDomainsLimited = $true + } + + # Check if the configurations are as recommended + $isCompliant = -not $externalAccessConfig.AllowTeamsConsumer -and -not $externalAccessConfig.AllowPublicUsers -and (-not $externalAccessConfig.AllowFederatedUsers -or $allowedDomainsLimited) + + # Create an instance of CISAuditResult and populate it + $params = @{ + Rec = $recnum + Result = $isCompliant + Status = if ($isCompliant) { "Pass" } else { "Fail" } + Details = "AllowTeamsConsumer: $($externalAccessConfig.AllowTeamsConsumer); AllowPublicUsers: $($externalAccessConfig.AllowPublicUsers); AllowFederatedUsers: $($externalAccessConfig.AllowFederatedUsers); AllowedDomains limited: $allowedDomainsLimited" + FailureReason = if (-not $isCompliant) { "One or more external access configurations are not compliant." } else { "N/A" } + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - # Check if the configurations are as recommended - $isCompliant = -not $externalAccessConfig.AllowTeamsConsumer -and -not $externalAccessConfig.AllowPublicUsers -and (-not $externalAccessConfig.AllowFederatedUsers -or $allowedDomainsLimited) - - # Create an instance of CISAuditResult and populate it - $params = @{ - Rec = "8.2.1" - Result = $isCompliant - Status = if ($isCompliant) { "Pass" } else { "Fail" } - Details = "AllowTeamsConsumer: $($externalAccessConfig.AllowTeamsConsumer); AllowPublicUsers: $($externalAccessConfig.AllowPublicUsers); AllowFederatedUsers: $($externalAccessConfig.AllowFederatedUsers); AllowedDomains limited: $allowedDomainsLimited" - FailureReason = if (-not $isCompliant) { "One or more external access configurations are not compliant." } else { "N/A" } + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-TeamsExternalFileSharing.ps1 b/source/tests/Test-TeamsExternalFileSharing.ps1 index fd4e653..1d5a135 100644 --- a/source/tests/Test-TeamsExternalFileSharing.ps1 +++ b/source/tests/Test-TeamsExternalFileSharing.ps1 @@ -11,36 +11,45 @@ function Test-TeamsExternalFileSharing { # Initialization code, if needed $auditResult = [CISAuditResult]::new() + $recnum = "8.1.1" } process { - # 8.1.1 (L2) Ensure external file sharing in Teams is enabled for only approved cloud storage services - # Connect to Teams PowerShell using Connect-MicrosoftTeams + try { + # 8.1.1 (L2) Ensure external file sharing in Teams is enabled for only approved cloud storage services + # Connect to Teams PowerShell using Connect-MicrosoftTeams - # Assuming that 'approvedProviders' is a list of approved cloud storage service names - # This list must be defined according to your organization's approved cloud storage services - $approvedProviders = @("AllowDropBox", "AllowBox", "AllowGoogleDrive", "AllowShareFile", "AllowEgnyte") - $clientConfig = Get-CsTeamsClientConfiguration + # Assuming that 'approvedProviders' is a list of approved cloud storage service names + # This list must be defined according to your organization's approved cloud storage services + $approvedProviders = @("AllowDropBox", "AllowBox", "AllowGoogleDrive", "AllowShareFile", "AllowEgnyte") + $clientConfig = Get-CsTeamsClientConfiguration - $isCompliant = $true - $nonCompliantProviders = @() + $isCompliant = $true + $nonCompliantProviders = @() - foreach ($provider in $approvedProviders) { - if (-not $clientConfig.$provider) { - $isCompliant = $false - $nonCompliantProviders += $provider + foreach ($provider in $approvedProviders) { + if (-not $clientConfig.$provider) { + $isCompliant = $false + $nonCompliantProviders += $provider + } } - } - # Create an instance of CISAuditResult and populate it - $params = @{ - Rec = "8.1.1" - Result = $isCompliant - Status = if ($isCompliant) { "Pass" } else { "Fail" } - Details = if (-not $isCompliant) { "Non-approved providers enabled: $($nonCompliantProviders -join ', ')" } else { "All cloud storage services are approved providers" } - FailureReason = if (-not $isCompliant) { "The following non-approved providers are enabled: $($nonCompliantProviders -join ', ')" } else { "N/A" } + # Create an instance of CISAuditResult and populate it + $params = @{ + Rec = $recnum + Result = $isCompliant + Status = if ($isCompliant) { "Pass" } else { "Fail" } + Details = if (-not $isCompliant) { "Non-approved providers enabled: $($nonCompliantProviders -join ', ')" } else { "All cloud storage services are approved providers" } + FailureReason = if (-not $isCompliant) { "The following non-approved providers are enabled: $($nonCompliantProviders -join ', ')" } else { "N/A" } + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + Write-Error "An error occurred during the test: $_" + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params } end { From df89e23bc1d76f93499eb0361ca2624d899e26ce Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:07:19 -0500 Subject: [PATCH 02/45] add: simplified object build call --- source/tests/Test-BlockMailForwarding.ps1 | 5 ++- source/tests/Test-MailboxAuditingE5.ps1 | 46 +++++++++++------------ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index 5554b32..54fe9c2 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -9,6 +9,7 @@ function Test-BlockMailForwarding { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed + $recnum = "6.2.1" } process { @@ -37,7 +38,7 @@ function Test-BlockMailForwarding { } $params = @{ - Rec = "6.2.1" + Rec = $recnum Result = $forwardingBlocked Status = if ($forwardingBlocked) { "Pass" } else { "Fail" } Details = $details @@ -49,7 +50,7 @@ function Test-BlockMailForwarding { Write-Error "An error occurred during the test: $_" # Call Initialize-CISAuditResult with error parameters - $auditResult = Initialize-CISAuditResult -Rec "6.2.1" -Failure + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } } diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index 3c5e949..3c84096 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -25,10 +25,10 @@ function Test-MailboxAuditingE5 { process { try { - foreach ($user in $allUsers) { - if ($processedUsers.ContainsKey($user.UserPrincipalName)) { - continue - } + foreach ($user in $allUsers) { + if ($processedUsers.ContainsKey($user.UserPrincipalName)) { + continue + } $licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName @@ -69,28 +69,28 @@ function Test-MailboxAuditingE5 { Write-Verbose "User $($user.UserPrincipalName) does not have an Office E5 license." } + } + + # Prepare failure reasons and details based on compliance + $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } + $details = if ($allFailures.Count -eq 0) { "All Office E5 users have correct mailbox audit settings." } else { $allFailures -join " | " } + + # Populate the audit result + $params = @{ + Rec = $recnum + Result = $allFailures.Count -eq 0 + Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - # Prepare failure reasons and details based on compliance - $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } - $details = if ($allFailures.Count -eq 0) { "All Office E5 users have correct mailbox audit settings." } else { $allFailures -join " | " } - - # Populate the audit result - $params = @{ - Rec = $recnum - Result = $allFailures.Count -eq 0 - Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - $auditResult = Initialize-CISAuditResult @params - } - catch { - Write-Error "An error occurred during the test: $_" - - # Call Initialize-CISAuditResult with error parameters - $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure - } } end { From 2712f7841247a09edaf064a67053bf7867e3edd7 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:05:21 -0500 Subject: [PATCH 03/45] docs: update CHANGELOG --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2c164..546b8f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ The format is based on and uses the types of changes according to [Keep a Change ### Added +- Updated test definitions for CIS Microsoft 365 Foundations Benchmark for better error handling and object output when errors occur. +- Added a parameter to the `Initialize-CISAuditResult` function to allow for a static failed object to be created when an error occurs. + +### Fixed + + + +## [0.1.4] - 2024-05-30 + +### Added + - Test definitions filter function. - Logging function for future use. - Test grade written to console. From a9e44a7c6f43a8fddc6b76d12abc41edb3c86886 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:07:04 -0500 Subject: [PATCH 04/45] fix: Removed nested functions in 6.1.2/6.1.3 --- source/tests/Test-MailboxAuditingE3.ps1 | 27 ------------------------- source/tests/Test-MailboxAuditingE5.ps1 | 27 ------------------------- 2 files changed, 54 deletions(-) diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index eac96d6..9828941 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -91,30 +91,3 @@ function Test-MailboxAuditingE3 { return $auditResult } } - -function Format-MissingActions { - param ([array]$missingActions) - - $actionGroups = @{ - "Admin" = @() - "Delegate" = @() - "Owner" = @() - } - - foreach ($action in $missingActions) { - if ($action -match "(Admin|Delegate|Owner) action '([^']+)' missing") { - $type = $matches[1] - $actionName = $matches[2] - $actionGroups[$type] += $actionName - } - } - - $formattedResults = @() - foreach ($type in $actionGroups.Keys) { - if ($actionGroups[$type].Count -gt 0) { - $formattedResults += "$($type) actions missing: $($actionGroups[$type] -join ', ')" - } - } - - return $formattedResults -join '; ' -} diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index 3c84096..f38c008 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -97,30 +97,3 @@ function Test-MailboxAuditingE5 { return $auditResult } } - -function Format-MissingActions { - param ([array]$missingActions) - - $actionGroups = @{ - "Admin" = @() - "Delegate" = @() - "Owner" = @() - } - - foreach ($action in $missingActions) { - if ($action -match "(Admin|Delegate|Owner) action '([^']+)' missing") { - $type = $matches[1] - $actionName = $matches[2] - $actionGroups[$type] += $actionName - } - } - - $formattedResults = @() - foreach ($type in $actionGroups.Keys) { - if ($actionGroups[$type].Count -gt 0) { - $formattedResults += "$($type) actions missing: $($actionGroups[$type] -join ', ')" - } - } - - return $formattedResults -join '; ' -} From 06aeadaee53c982947be719c79099a8b00e22351 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:43:45 -0500 Subject: [PATCH 05/45] fix: connections in helper csv and connect function --- source/Private/Connect-M365Suite.ps1 | 4 ++-- source/helper/TestDefinitions.csv | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/Private/Connect-M365Suite.ps1 b/source/Private/Connect-M365Suite.ps1 index 97d9e4c..7727249 100644 --- a/source/Private/Connect-M365Suite.ps1 +++ b/source/Private/Connect-M365Suite.ps1 @@ -11,13 +11,13 @@ function Connect-M365Suite { $VerbosePreference = "SilentlyContinue" try { - if ($RequiredConnections -contains "AzureAD" -or $RequiredConnections -contains "AzureAD | EXO") { + if ($RequiredConnections -contains "AzureAD" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "AzureAD | EXO | Microsoft Graph") { Write-Host "Connecting to Azure Active Directory..." -ForegroundColor Cyan Connect-AzureAD | Out-Null Write-Host "Successfully connected to Azure Active Directory." -ForegroundColor Green } - if ($RequiredConnections -contains "Microsoft Graph") { + if ($RequiredConnections -contains "Microsoft Graph" -or $RequiredConnections -contains "AzureAD | EXO | Microsoft Graph") { Write-Host "Connecting to Microsoft Graph with scopes: Directory.Read.All, Domain.Read.All, Policy.Read.All, Organization.Read.All" -ForegroundColor Cyan try { Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome | Out-Null diff --git a/source/helper/TestDefinitions.csv b/source/helper/TestDefinitions.csv index a284e76..b499047 100644 --- a/source/helper/TestDefinitions.csv +++ b/source/helper/TestDefinitions.csv @@ -18,8 +18,8 @@ 17,Test-RestrictTenantCreation.ps1,5.1.2.3,Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes',E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Graph 18,Test-PasswordHashSync.ps1,5.1.8.1,Ensure password hash sync is enabled for hybrid deployments,E3,L1,6.7,Centralize Access Control,FALSE,TRUE,TRUE,TRUE,Microsoft Graph 19,Test-AuditDisabledFalse.ps1,6.1.1,Ensure 'AuditDisabled' organizationally is set to 'False',E3,L1,8.2,Collect Audit Logs,TRUE,TRUE,TRUE,TRUE,Microsoft Graph -20,Test-MailboxAuditingE3.ps1,6.1.2,Ensure mailbox auditing for Office E3 users is Enabled,E3,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO -21,Test-MailboxAuditingE5.ps1,6.1.3,Ensure mailbox auditing for Office E5 users is Enabled,E5,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO +20,Test-MailboxAuditingE3.ps1,6.1.2,Ensure mailbox auditing for Office E3 users is Enabled,E3,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO | Microsoft Graph +21,Test-MailboxAuditingE5.ps1,6.1.3,Ensure mailbox auditing for Office E5 users is Enabled,E5,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO | Microsoft Graph 22,Test-BlockMailForwarding.ps1,6.2.1,Ensure all forms of mail forwarding are blocked and/or disabled,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO 23,Test-NoWhitelistDomains.ps1,6.2.2,Ensure mail transport rules do not whitelist specific domains,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO 24,Test-IdentifyExternalEmail.ps1,6.2.3,Ensure email from external senders is identified,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO From 8446d101a7f2f6ab1893b65744d53f77782239d1 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:40:45 -0500 Subject: [PATCH 06/45] fix: connections in helper csv and connect function --- source/Private/Connect-M365Suite.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Private/Connect-M365Suite.ps1 b/source/Private/Connect-M365Suite.ps1 index 7727249..468d068 100644 --- a/source/Private/Connect-M365Suite.ps1 +++ b/source/Private/Connect-M365Suite.ps1 @@ -30,7 +30,7 @@ function Connect-M365Suite { } } - if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO") { + if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO" -or $RequiredConnections -contains "AzureAD | EXO | Microsoft Graph") { Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan Connect-ExchangeOnline | Out-Null Write-Host "Successfully connected to Exchange Online." -ForegroundColor Green From 4bc1f8fddab1de0bb38c482cdbaf2fad6f785ee9 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:38:19 -0500 Subject: [PATCH 07/45] change: refactored test output and created new functions --- source/Private/Invoke-TestFunction.ps1 | 34 +++++ source/Private/Measure-AuditResult.ps1 | 31 ++++ source/Public/Invoke-M365SecurityAudit.ps1 | 135 ++++-------------- .../Test-AdministrativeAccountCompliance.ps1 | 6 + source/tests/Test-AntiPhishingPolicy.ps1 | 7 + source/tests/Test-AuditDisabledFalse.ps1 | 7 + source/tests/Test-AuditLogSearch.ps1 | 6 + source/tests/Test-BlockChannelEmails.ps1 | 6 + source/tests/Test-BlockMailForwarding.ps1 | 6 + .../tests/Test-BlockSharedMailboxSignIn.ps1 | 6 + source/tests/Test-CommonAttachmentFilter.ps1 | 6 + source/tests/Test-CustomerLockbox.ps1 | 6 + source/tests/Test-DialInBypassLobby.ps1 | 6 + .../Test-DisallowInfectedFilesDownload.ps1 | 6 + source/tests/Test-EnableDKIM.ps1 | 6 + source/tests/Test-ExternalNoControl.ps1 | 6 + .../tests/Test-ExternalSharingCalendars.ps1 | 6 + source/tests/Test-GlobalAdminsCount.ps1 | 6 + source/tests/Test-GuestAccessExpiration.ps1 | 6 + .../tests/Test-GuestUsersBiweeklyReview.ps1 | 6 + source/tests/Test-IdentifyExternalEmail.ps1 | 6 + source/tests/Test-LinkSharingRestrictions.ps1 | 6 + source/tests/Test-MailTipsEnabled.ps1 | 6 + source/tests/Test-MailboxAuditingE3.ps1 | 6 + source/tests/Test-MailboxAuditingE5.ps1 | 6 + .../Test-ManagedApprovedPublicGroups.ps1 | 6 + source/tests/Test-MeetingChatNoAnonymous.ps1 | 6 + .../tests/Test-ModernAuthExchangeOnline.ps1 | 6 + source/tests/Test-ModernAuthSharePoint.ps1 | 6 + source/tests/Test-NoAnonymousMeetingJoin.ps1 | 62 ++++---- source/tests/Test-NoAnonymousMeetingStart.ps1 | 6 + source/tests/Test-NoWhitelistDomains.ps1 | 6 + source/tests/Test-NotifyMalwareInternal.ps1 | 80 ++++++----- .../Test-OneDriveContentRestrictions.ps1 | 6 + .../tests/Test-OneDriveSyncRestrictions.ps1 | 6 + source/tests/Test-OrgOnlyBypassLobby.ps1 | 6 + source/tests/Test-OrganizersPresent.ps1 | 70 ++++----- source/tests/Test-PasswordHashSync.ps1 | 64 +++++---- .../tests/Test-PasswordNeverExpirePolicy.ps1 | 6 + source/tests/Test-ReauthWithCode.ps1 | 6 + source/tests/Test-ReportSecurityInTeams.ps1 | 6 + source/tests/Test-RestrictCustomScripts.ps1 | 6 + source/tests/Test-RestrictExternalSharing.ps1 | 6 + source/tests/Test-RestrictOutlookAddins.ps1 | 6 + .../Test-RestrictStorageProvidersOutlook.ps1 | 72 +++++----- source/tests/Test-RestrictTenantCreation.ps1 | 6 + source/tests/Test-SafeAttachmentsPolicy.ps1 | 6 + source/tests/Test-SafeAttachmentsTeams.ps1 | 6 + source/tests/Test-SafeLinksOfficeApps.ps1 | 6 + source/tests/Test-SharePointAADB2B.ps1 | 6 + .../Test-SharePointExternalSharingDomains.ps1 | 6 + .../Test-SharePointGuestsItemSharing.ps1 | 6 + source/tests/Test-SpamPolicyAdminNotify.ps1 | 6 + source/tests/Test-TeamsExternalAccess.ps1 | 6 + .../tests/Test-TeamsExternalFileSharing.ps1 | 6 + .../Private/Invoke-TestFunction.tests.ps1 | 27 ++++ .../Private/Measure-AuditResult.tests.ps1 | 27 ++++ 57 files changed, 617 insertions(+), 269 deletions(-) create mode 100644 source/Private/Invoke-TestFunction.ps1 create mode 100644 source/Private/Measure-AuditResult.ps1 create mode 100644 tests/Unit/Private/Invoke-TestFunction.tests.ps1 create mode 100644 tests/Unit/Private/Measure-AuditResult.tests.ps1 diff --git a/source/Private/Invoke-TestFunction.ps1 b/source/Private/Invoke-TestFunction.ps1 new file mode 100644 index 0000000..2dea2d0 --- /dev/null +++ b/source/Private/Invoke-TestFunction.ps1 @@ -0,0 +1,34 @@ +function Invoke-TestFunction { + param ( + [Parameter(Mandatory = $true)] + [PSObject]$FunctionFile, + + [Parameter(Mandatory = $true)] + [string]$DomainName + ) + + $functionName = $FunctionFile.BaseName + $functionCmd = Get-Command -Name $functionName + + # Check if the test function needs DomainName parameter + $paramList = @{} + if ('DomainName' -in $functionCmd.Parameters.Keys) { + $paramList.DomainName = $DomainName + } + + # Use splatting to pass parameters + Write-Host "Running $functionName..." + try { + $result = & $functionName @paramList + # Assuming each function returns an array of CISAuditResult or a single CISAuditResult + return $result + } + catch { + Write-Error "An error occurred during the test: $_" + $script:FailedTests.Add([PSCustomObject]@{ Test = $functionName; Error = $_ }) + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $functionName -Failure + return $auditResult + } +} diff --git a/source/Private/Measure-AuditResult.ps1 b/source/Private/Measure-AuditResult.ps1 new file mode 100644 index 0000000..d03265e --- /dev/null +++ b/source/Private/Measure-AuditResult.ps1 @@ -0,0 +1,31 @@ +function Measure-AuditResult { + param ( + [Parameter(Mandatory = $true)] + [System.Collections.ArrayList]$AllAuditResults, + + [Parameter(Mandatory = $false)] + [System.Collections.ArrayList]$FailedTests + ) + + # Calculate the total number of tests + $totalTests = $AllAuditResults.Count + + # Calculate the number of passed tests + $passedTests = $AllAuditResults.ToArray() | Where-Object { $_.Result -eq $true } | Measure-Object | Select-Object -ExpandProperty Count + + # Calculate the pass percentage + $passPercentage = if ($totalTests -eq 0) { 0 } else { [math]::Round(($passedTests / $totalTests) * 100, 2) } + + # Display the pass percentage to the user + Write-Host "Audit completed. $passedTests out of $totalTests tests passed." -ForegroundColor Cyan + Write-Host "Your passing percentage is $passPercentage%." + + # Display details of failed tests + if ($FailedTests.Count -gt 0) { + Write-Host "The following tests failed to complete:" -ForegroundColor Red + foreach ($failedTest in $FailedTests) { + Write-Host "Test: $($failedTest.Test)" -ForegroundColor Yellow + Write-Host "Error: $($failedTest.Error)" -ForegroundColor Yellow + } + } +} diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index e8a29ee..682bfdd 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -1,64 +1,3 @@ -<# - .SYNOPSIS - Invokes a security audit for Microsoft 365 environments. - .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. - .PARAMETER DomainName - The domain name of the Microsoft 365 environment. This parameter is mandatory. - .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 - Specifies the profile level (L1 or L2) for the audit. This parameter is optional and can be combined with the ELevel parameter. - .PARAMETER IncludeIG1 - If specified, includes tests where IG1 is true. - .PARAMETER IncludeIG2 - If specified, includes tests where IG2 is true. - .PARAMETER IncludeIG3 - If specified, includes tests where IG3 is true. - .PARAMETER IncludeRecommendation - Specifies specific recommendations to include in the audit. Accepts an array of recommendation numbers. - .PARAMETER SkipRecommendation - Specifies specific recommendations to exclude from the audit. Accepts an array of recommendation numbers. - .PARAMETER DoNotConnect - If specified, the cmdlet will not establish a connection to Microsoft 365 services. - .PARAMETER DoNotDisconnect - If specified, the cmdlet will not disconnect from Microsoft 365 services after execution. - .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" - - Performs a security audit for the E5 level and L1 profile in the specified Microsoft 365 environment. - .EXAMPLE - PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -IncludeIG1 - - Performs an audit including all tests where IG1 is true. - .EXAMPLE - PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -SkipRecommendation '1.1.3', '2.1.1' - - Performs an audit while excluding specific recommendations 1.1.3 and 2.1.1. - .EXAMPLE - PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" - PS> $auditResults | Export-Csv -Path "auditResults.csv" -NoTypeInformation - - Captures the audit results into a variable and exports them to a CSV file. - .INPUTS - None. You cannot pipe objects to Invoke-M365SecurityAudit. - .OUTPUTS - CISAuditResult[] - The cmdlet returns an array of CISAuditResult objects representing the results of the security audit. - .NOTES - - This module is based on CIS benchmarks. - - Governed by the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. - - Commercial use is not permitted. This module cannot be sold or used for commercial purposes. - - Modifications and sharing are allowed under the same license. - - For full license details, visit: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en - - Register for CIS Benchmarks at: https://www.cisecurity.org/cis-benchmarks - .LINK - https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit -#> function Invoke-M365SecurityAudit { [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')] [OutputType([CISAuditResult[]])] @@ -92,12 +31,12 @@ function Invoke-M365SecurityAudit { [Parameter(Mandatory = $true, ParameterSetName = 'RecFilter')] [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', ` - '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', ` - '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', ` - '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' + '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', ` + '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', ` + '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' )] [string[]]$IncludeRecommendation, @@ -105,12 +44,12 @@ function Invoke-M365SecurityAudit { [Parameter(Mandatory = $true, ParameterSetName = 'SkipRecFilter')] [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', ` - '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', ` - '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', ` - '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' + '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', ` + '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', ` + '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' )] [string[]]$SkipRecommendation, @@ -120,14 +59,11 @@ function Invoke-M365SecurityAudit { [switch]$NoModuleCheck ) - - Begin { if ($script:MaximumFunctionCount -lt 8192) { $script:MaximumFunctionCount = 8192 } # Ensure required modules are installed - # Define the required modules and versions in a hashtable if (!($NoModuleCheck)) { $requiredModules = @( @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0" }, @@ -147,16 +83,12 @@ function Invoke-M365SecurityAudit { } } - - # Loop through each required module and assert its availability - - # Establishing connections - # Load test definitions from CSV $testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath "helper\TestDefinitions.csv" $testDefinitions = Import-Csv -Path $testDefinitionsPath # Load the Test Definitions into the script scope for use in other functions $script:TestDefinitionsObject = $testDefinitions + # Apply filters based on parameter sets $params = @{ TestDefinitions = $testDefinitions @@ -167,7 +99,7 @@ function Invoke-M365SecurityAudit { SkipRecommendation = $SkipRecommendation } $testDefinitions = Get-TestDefinitionsObject @params - # End switch ($PSCmdlet.ParameterSetName) + # Extract unique connections needed $requiredConnections = $testDefinitions.Connection | Sort-Object -Unique @@ -175,17 +107,19 @@ function Invoke-M365SecurityAudit { if (!($DoNotConnect)) { Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections } + # Determine which test files to load based on filtering $testsToLoad = $testDefinitions.TestFileName | ForEach-Object { $_ -replace '.ps1$', '' } - # Display the tests that would be loaded if the function is called with -WhatIf - Write-Verbose "The $(($testsToLoad).count) test/s that would be loaded based on filter criteria:" $testsToLoad | ForEach-Object { Write-Verbose " $_" } + + # 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 + $allAuditResults = [System.Collections.ArrayList]::new() # Initialize a collection to hold all results # Dynamically dot-source the test scripts $testsFolderPath = Join-Path -Path $PSScriptRoot -ChildPath "tests" @@ -199,26 +133,16 @@ function Invoke-M365SecurityAudit { } Catch { Write-Error "Failed to load test function $($_.Name): $_" + $script:FailedTests.Add([PSCustomObject]@{ Test = $_.Name; Error = $_ }) } } # Execute each test function from the prepared list foreach ($testFunction in $testFiles) { $functionName = $testFunction.BaseName - $functionCmd = Get-Command -Name $functionName - - # Check if the test function needs DomainName parameter - $paramList = @{} - if ('DomainName' -in $functionCmd.Parameters.Keys) { - $paramList.DomainName = $DomainName - } - - # Use splatting to pass parameters if ($PSCmdlet.ShouldProcess($functionName, "Execute test")) { - Write-Host "Running $functionName..." - $result = & $functionName @paramList - # Assuming each function returns an array of CISAuditResult or a single CISAuditResult - [void]($allAuditResults.add($Result)) + $auditResult = Invoke-TestFunction -FunctionFile $testFunction -DomainName $DomainName + [void]$allAuditResults.Add($auditResult) } } } @@ -228,20 +152,11 @@ function Invoke-M365SecurityAudit { # Clean up sessions Disconnect-M365Suite -RequiredConnections $requiredConnections } - # Calculate the total number of tests - $totalTests = $allAuditResults.Count - # Calculate the number of passed tests - $passedTests = $allAuditResults.ToArray() | Where-Object { $_.Result -eq $true } | Measure-Object | Select-Object -ExpandProperty Count + # Call the private function to calculate and display results + Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests - # Calculate the pass percentage - $passPercentage = if ($totalTests -eq 0) { 0 } else { [math]::Round(($passedTests / $totalTests) * 100, 2) } - - # Display the pass percentage to the user - Write-Host "Audit completed. $passedTests out of $totalTests tests passed." -ForegroundColor Cyan - Write-Host "Your passing percentage is $passPercentage%." # Return all collected audit results return $allAuditResults.ToArray() - # Check if the Disconnect switch is present } -} \ No newline at end of file +} diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 05b3796..ff1aeee 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -79,6 +79,12 @@ function Test-AdministrativeAccountCompliance { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-AntiPhishingPolicy.ps1 b/source/tests/Test-AntiPhishingPolicy.ps1 index ccbf02f..c36b20c 100644 --- a/source/tests/Test-AntiPhishingPolicy.ps1 +++ b/source/tests/Test-AntiPhishingPolicy.ps1 @@ -76,6 +76,13 @@ function Test-AntiPhishingPolicy { } catch { Write-Error "An error occurred during the test: $_" + + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-AuditDisabledFalse.ps1 b/source/tests/Test-AuditDisabledFalse.ps1 index c2c2dcc..e8c4688 100644 --- a/source/tests/Test-AuditDisabledFalse.ps1 +++ b/source/tests/Test-AuditDisabledFalse.ps1 @@ -48,6 +48,13 @@ function Test-AuditDisabledFalse { } catch { Write-Error "An error occurred during the test: $_" + + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-AuditLogSearch.ps1 b/source/tests/Test-AuditLogSearch.ps1 index 69f2c8f..2ffec8a 100644 --- a/source/tests/Test-AuditLogSearch.ps1 +++ b/source/tests/Test-AuditLogSearch.ps1 @@ -49,6 +49,12 @@ function Test-AuditLogSearch { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-BlockChannelEmails.ps1 b/source/tests/Test-BlockChannelEmails.ps1 index 39884d7..623a882 100644 --- a/source/tests/Test-BlockChannelEmails.ps1 +++ b/source/tests/Test-BlockChannelEmails.ps1 @@ -49,6 +49,12 @@ function Test-BlockChannelEmails { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index 54fe9c2..dbe539a 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -49,6 +49,12 @@ function Test-BlockMailForwarding { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-BlockSharedMailboxSignIn.ps1 b/source/tests/Test-BlockSharedMailboxSignIn.ps1 index a8d763a..5561a3d 100644 --- a/source/tests/Test-BlockSharedMailboxSignIn.ps1 +++ b/source/tests/Test-BlockSharedMailboxSignIn.ps1 @@ -51,6 +51,12 @@ function Test-BlockSharedMailboxSignIn { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-CommonAttachmentFilter.ps1 b/source/tests/Test-CommonAttachmentFilter.ps1 index b328491..662529a 100644 --- a/source/tests/Test-CommonAttachmentFilter.ps1 +++ b/source/tests/Test-CommonAttachmentFilter.ps1 @@ -48,6 +48,12 @@ function Test-CommonAttachmentFilter { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-CustomerLockbox.ps1 b/source/tests/Test-CustomerLockbox.ps1 index a540f1b..b22773b 100644 --- a/source/tests/Test-CustomerLockbox.ps1 +++ b/source/tests/Test-CustomerLockbox.ps1 @@ -49,6 +49,12 @@ function Test-CustomerLockbox { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-DialInBypassLobby.ps1 b/source/tests/Test-DialInBypassLobby.ps1 index efd83fa..d9449b4 100644 --- a/source/tests/Test-DialInBypassLobby.ps1 +++ b/source/tests/Test-DialInBypassLobby.ps1 @@ -49,6 +49,12 @@ function Test-DialInBypassLobby { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-DisallowInfectedFilesDownload.ps1 b/source/tests/Test-DisallowInfectedFilesDownload.ps1 index 963813d..538e998 100644 --- a/source/tests/Test-DisallowInfectedFilesDownload.ps1 +++ b/source/tests/Test-DisallowInfectedFilesDownload.ps1 @@ -50,6 +50,12 @@ function Test-DisallowInfectedFilesDownload { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-EnableDKIM.ps1 b/source/tests/Test-EnableDKIM.ps1 index 7661073..db793c5 100644 --- a/source/tests/Test-EnableDKIM.ps1 +++ b/source/tests/Test-EnableDKIM.ps1 @@ -50,6 +50,12 @@ function Test-EnableDKIM { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-ExternalNoControl.ps1 b/source/tests/Test-ExternalNoControl.ps1 index 0afec63..0fce827 100644 --- a/source/tests/Test-ExternalNoControl.ps1 +++ b/source/tests/Test-ExternalNoControl.ps1 @@ -50,6 +50,12 @@ function Test-ExternalNoControl { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-ExternalSharingCalendars.ps1 b/source/tests/Test-ExternalSharingCalendars.ps1 index 2685a5c..3f0c7a6 100644 --- a/source/tests/Test-ExternalSharingCalendars.ps1 +++ b/source/tests/Test-ExternalSharingCalendars.ps1 @@ -59,6 +59,12 @@ function Test-ExternalSharingCalendars { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index ea39bfd..1a7525e 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -50,6 +50,12 @@ function Test-GlobalAdminsCount { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-GuestAccessExpiration.ps1 b/source/tests/Test-GuestAccessExpiration.ps1 index 4f4aaca..cef642f 100644 --- a/source/tests/Test-GuestAccessExpiration.ps1 +++ b/source/tests/Test-GuestAccessExpiration.ps1 @@ -45,6 +45,12 @@ function Test-GuestAccessExpiration { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-GuestUsersBiweeklyReview.ps1 b/source/tests/Test-GuestUsersBiweeklyReview.ps1 index 23b2d74..0aeb409 100644 --- a/source/tests/Test-GuestUsersBiweeklyReview.ps1 +++ b/source/tests/Test-GuestUsersBiweeklyReview.ps1 @@ -51,6 +51,12 @@ function Test-GuestUsersBiweeklyReview { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-IdentifyExternalEmail.ps1 b/source/tests/Test-IdentifyExternalEmail.ps1 index e275bc1..6c43794 100644 --- a/source/tests/Test-IdentifyExternalEmail.ps1 +++ b/source/tests/Test-IdentifyExternalEmail.ps1 @@ -45,6 +45,12 @@ function Test-IdentifyExternalEmail { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-LinkSharingRestrictions.ps1 b/source/tests/Test-LinkSharingRestrictions.ps1 index ad106bf..cc96c15 100644 --- a/source/tests/Test-LinkSharingRestrictions.ps1 +++ b/source/tests/Test-LinkSharingRestrictions.ps1 @@ -45,6 +45,12 @@ function Test-LinkSharingRestrictions { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-MailTipsEnabled.ps1 b/source/tests/Test-MailTipsEnabled.ps1 index d6c2684..c093dea 100644 --- a/source/tests/Test-MailTipsEnabled.ps1 +++ b/source/tests/Test-MailTipsEnabled.ps1 @@ -51,6 +51,12 @@ function Test-MailTipsEnabled { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index 9828941..fb9e129 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -82,6 +82,12 @@ function Test-MailboxAuditingE3 { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index f38c008..df8f145 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -88,6 +88,12 @@ function Test-MailboxAuditingE5 { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-ManagedApprovedPublicGroups.ps1 b/source/tests/Test-ManagedApprovedPublicGroups.ps1 index d471042..94512ff 100644 --- a/source/tests/Test-ManagedApprovedPublicGroups.ps1 +++ b/source/tests/Test-ManagedApprovedPublicGroups.ps1 @@ -48,6 +48,12 @@ function Test-ManagedApprovedPublicGroups { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-MeetingChatNoAnonymous.ps1 b/source/tests/Test-MeetingChatNoAnonymous.ps1 index b7f1f98..12764be 100644 --- a/source/tests/Test-MeetingChatNoAnonymous.ps1 +++ b/source/tests/Test-MeetingChatNoAnonymous.ps1 @@ -45,6 +45,12 @@ function Test-MeetingChatNoAnonymous { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-ModernAuthExchangeOnline.ps1 b/source/tests/Test-ModernAuthExchangeOnline.ps1 index 5210b18..2c5c79e 100644 --- a/source/tests/Test-ModernAuthExchangeOnline.ps1 +++ b/source/tests/Test-ModernAuthExchangeOnline.ps1 @@ -43,6 +43,12 @@ function Test-ModernAuthExchangeOnline { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-ModernAuthSharePoint.ps1 b/source/tests/Test-ModernAuthSharePoint.ps1 index cb51f46..990a64d 100644 --- a/source/tests/Test-ModernAuthSharePoint.ps1 +++ b/source/tests/Test-ModernAuthSharePoint.ps1 @@ -41,6 +41,12 @@ function Test-ModernAuthSharePoint { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-NoAnonymousMeetingJoin.ps1 b/source/tests/Test-NoAnonymousMeetingJoin.ps1 index ce430ca..6a9336a 100644 --- a/source/tests/Test-NoAnonymousMeetingJoin.ps1 +++ b/source/tests/Test-NoAnonymousMeetingJoin.ps1 @@ -14,39 +14,45 @@ function Test-NoAnonymousMeetingJoin { process { try { - # 8.5.1 (L2) Ensure anonymous users can't join a meeting + # 8.5.1 (L2) Ensure anonymous users can't join a meeting - # Connect to Teams PowerShell using Connect-MicrosoftTeams + # Connect to Teams PowerShell using Connect-MicrosoftTeams - $teamsMeetingPolicy = Get-CsTeamsMeetingPolicy -Identity Global - $allowAnonymousUsersToJoinMeeting = $teamsMeetingPolicy.AllowAnonymousUsersToJoinMeeting + $teamsMeetingPolicy = Get-CsTeamsMeetingPolicy -Identity Global + $allowAnonymousUsersToJoinMeeting = $teamsMeetingPolicy.AllowAnonymousUsersToJoinMeeting - # Prepare failure reasons and details based on compliance - $failureReasons = if ($allowAnonymousUsersToJoinMeeting) { - "Anonymous users are allowed to join meetings" + # Prepare failure reasons and details based on compliance + $failureReasons = if ($allowAnonymousUsersToJoinMeeting) { + "Anonymous users are allowed to join meetings" + } + else { + "N/A" + } + + $details = "AllowAnonymousUsersToJoinMeeting is set to $allowAnonymousUsersToJoinMeeting" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = -not $allowAnonymousUsersToJoinMeeting + Status = if (-not $allowAnonymousUsersToJoinMeeting) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } - else { - "N/A" + catch { + Write-Error "An error occurred during the test: $_" + + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - - $details = "AllowAnonymousUsersToJoinMeeting is set to $allowAnonymousUsersToJoinMeeting" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = $recnum - Result = -not $allowAnonymousUsersToJoinMeeting - Status = if (-not $allowAnonymousUsersToJoinMeeting) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params - } - catch { - Write-Error "An error occurred during the test: $_" - - # Call Initialize-CISAuditResult with error parameters - $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure - } } end { diff --git a/source/tests/Test-NoAnonymousMeetingStart.ps1 b/source/tests/Test-NoAnonymousMeetingStart.ps1 index d9d1441..9820b84 100644 --- a/source/tests/Test-NoAnonymousMeetingStart.ps1 +++ b/source/tests/Test-NoAnonymousMeetingStart.ps1 @@ -44,6 +44,12 @@ function Test-NoAnonymousMeetingStart { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-NoWhitelistDomains.ps1 b/source/tests/Test-NoWhitelistDomains.ps1 index 92652be..fe9ea6b 100644 --- a/source/tests/Test-NoWhitelistDomains.ps1 +++ b/source/tests/Test-NoWhitelistDomains.ps1 @@ -48,6 +48,12 @@ function Test-NoWhitelistDomains { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-NotifyMalwareInternal.ps1 b/source/tests/Test-NotifyMalwareInternal.ps1 index e09a4b6..eba1e84 100644 --- a/source/tests/Test-NotifyMalwareInternal.ps1 +++ b/source/tests/Test-NotifyMalwareInternal.ps1 @@ -14,52 +14,58 @@ function Test-NotifyMalwareInternal { process { try { - # 2.1.3 Ensure notifications for internal users sending malware is Enabled + # 2.1.3 Ensure notifications for internal users sending malware is Enabled - # Retrieve all 'Custom' malware filter policies and check notification settings - $malwareNotifications = Get-MalwareFilterPolicy | Where-Object { $_.RecommendedPolicyType -eq 'Custom' } - $policiesToReport = @() + # Retrieve all 'Custom' malware filter policies and check notification settings + $malwareNotifications = Get-MalwareFilterPolicy | Where-Object { $_.RecommendedPolicyType -eq 'Custom' } + $policiesToReport = @() - foreach ($policy in $malwareNotifications) { - if ($policy.EnableInternalSenderAdminNotifications -ne $true) { - $policiesToReport += "$($policy.Identity): Notifications Disabled" + foreach ($policy in $malwareNotifications) { + if ($policy.EnableInternalSenderAdminNotifications -ne $true) { + $policiesToReport += "$($policy.Identity): Notifications Disabled" + } } - } - # Determine the result based on the presence of custom policies without notifications - $result = $policiesToReport.Count -eq 0 + # Determine the result based on the presence of custom policies without notifications + $result = $policiesToReport.Count -eq 0 - # Prepare failure reasons and details based on compliance - $failureReasons = if ($result) { - "N/A" - } - else { - "Some custom policies do not have notifications for internal users sending malware enabled." - } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($result) { + "N/A" + } + else { + "Some custom policies do not have notifications for internal users sending malware enabled." + } - $details = if ($result) { - "All custom malware policies have notifications enabled." - } - else { - "Misconfigured Policies: $($policiesToReport -join ', ')" - } + $details = if ($result) { + "All custom malware policies have notifications enabled." + } + else { + "Misconfigured Policies: $($policiesToReport -join ', ')" + } - # Create and populate the CISAuditResult object - $params = @{ - Rec = $recnum - Result = $result - Status = if ($result) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } - $auditResult = Initialize-CISAuditResult @params - } - catch { - Write-Error "An error occurred during the test: $_" + catch { + Write-Error "An error occurred during the test: $_" - # Call Initialize-CISAuditResult with error parameters - $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure - } + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-OneDriveContentRestrictions.ps1 b/source/tests/Test-OneDriveContentRestrictions.ps1 index 136f951..5d10b50 100644 --- a/source/tests/Test-OneDriveContentRestrictions.ps1 +++ b/source/tests/Test-OneDriveContentRestrictions.ps1 @@ -48,6 +48,12 @@ function Test-OneDriveContentRestrictions { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-OneDriveSyncRestrictions.ps1 b/source/tests/Test-OneDriveSyncRestrictions.ps1 index dbea815..b0af3df 100644 --- a/source/tests/Test-OneDriveSyncRestrictions.ps1 +++ b/source/tests/Test-OneDriveSyncRestrictions.ps1 @@ -48,6 +48,12 @@ function Test-OneDriveSyncRestrictions { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-OrgOnlyBypassLobby.ps1 b/source/tests/Test-OrgOnlyBypassLobby.ps1 index 1f6a6b3..9ad8958 100644 --- a/source/tests/Test-OrgOnlyBypassLobby.ps1 +++ b/source/tests/Test-OrgOnlyBypassLobby.ps1 @@ -50,6 +50,12 @@ function Test-OrgOnlyBypassLobby { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-OrganizersPresent.ps1 b/source/tests/Test-OrganizersPresent.ps1 index e0215f5..8e2fead 100644 --- a/source/tests/Test-OrganizersPresent.ps1 +++ b/source/tests/Test-OrganizersPresent.ps1 @@ -14,45 +14,51 @@ function Test-OrganizersPresent { process { try { - # 8.5.6 (L2) Ensure only organizers and co-organizers can present + # 8.5.6 (L2) Ensure only organizers and co-organizers can present - # Connect to Teams PowerShell using Connect-MicrosoftTeams + # Connect to Teams PowerShell using Connect-MicrosoftTeams - # Retrieve the Teams meeting policy for presenters - $CsTeamsMeetingPolicyPresenters = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property DesignatedPresenterRoleMode - $presenterRoleRestricted = $CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode -eq 'OrganizerOnlyUserOverride' + # Retrieve the Teams meeting policy for presenters + $CsTeamsMeetingPolicyPresenters = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property DesignatedPresenterRoleMode + $presenterRoleRestricted = $CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode -eq 'OrganizerOnlyUserOverride' - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $presenterRoleRestricted) { - "Others besides organizers and co-organizers can present" - } - else { - "N/A" + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $presenterRoleRestricted) { + "Others besides organizers and co-organizers can present" + } + else { + "N/A" + } + + $details = if ($presenterRoleRestricted) { + "Only organizers and co-organizers can present." + } + else { + "DesignatedPresenterRoleMode is set to $($CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode)" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $presenterRoleRestricted + Status = if ($presenterRoleRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = if ($presenterRoleRestricted) { - "Only organizers and co-organizers can present." - } - else { - "DesignatedPresenterRoleMode is set to $($CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode)" - } + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } - # Create and populate the CISAuditResult object - $params = @{ - Rec = $recnum - Result = $presenterRoleRestricted - Status = if ($presenterRoleRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params - } - catch { - Write-Error "An error occurred during the test: $_" + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) - # Call Initialize-CISAuditResult with error parameters - $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure - } + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-PasswordHashSync.ps1 b/source/tests/Test-PasswordHashSync.ps1 index 42afa1c..dfde80f 100644 --- a/source/tests/Test-PasswordHashSync.ps1 +++ b/source/tests/Test-PasswordHashSync.ps1 @@ -14,39 +14,45 @@ function Test-PasswordHashSync { process { try { - # 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments - # Pass if OnPremisesSyncEnabled is True. Fail otherwise. + # 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments + # Pass if OnPremisesSyncEnabled is True. Fail otherwise. - # Retrieve password hash sync status - $passwordHashSync = Get-MgOrganization | Select-Object -ExpandProperty OnPremisesSyncEnabled - $hashSyncResult = $passwordHashSync + # Retrieve password hash sync status + $passwordHashSync = Get-MgOrganization | Select-Object -ExpandProperty OnPremisesSyncEnabled + $hashSyncResult = $passwordHashSync - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $hashSyncResult) { - "Password hash sync for hybrid deployments is not enabled" + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $hashSyncResult) { + "Password hash sync for hybrid deployments is not enabled" + } + else { + "N/A" + } + + $details = "OnPremisesSyncEnabled: $($passwordHashSync)" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $hashSyncResult + Status = if ($hashSyncResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } - else { - "N/A" + catch { + Write-Error "An error occurred during the test: $_" + + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } - - $details = "OnPremisesSyncEnabled: $($passwordHashSync)" - - # Create and populate the CISAuditResult object - $params = @{ - Rec = $recnum - Result = $hashSyncResult - Status = if ($hashSyncResult) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params - } - catch { - Write-Error "An error occurred during the test: $_" - - # Call Initialize-CISAuditResult with error parameters - $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure - } } end { diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index 63f2166..144a8d7 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -44,6 +44,12 @@ function Test-PasswordNeverExpirePolicy { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-ReauthWithCode.ps1 b/source/tests/Test-ReauthWithCode.ps1 index 5274b46..318bade 100644 --- a/source/tests/Test-ReauthWithCode.ps1 +++ b/source/tests/Test-ReauthWithCode.ps1 @@ -43,6 +43,12 @@ function Test-ReauthWithCode { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-ReportSecurityInTeams.ps1 b/source/tests/Test-ReportSecurityInTeams.ps1 index cc9c205..aceaf1b 100644 --- a/source/tests/Test-ReportSecurityInTeams.ps1 +++ b/source/tests/Test-ReportSecurityInTeams.ps1 @@ -53,6 +53,12 @@ function Test-ReportSecurityInTeams { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index cc3c051..5bc6f6c 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -58,6 +58,12 @@ function Test-RestrictCustomScripts { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-RestrictExternalSharing.ps1 b/source/tests/Test-RestrictExternalSharing.ps1 index a974262..0276204 100644 --- a/source/tests/Test-RestrictExternalSharing.ps1 +++ b/source/tests/Test-RestrictExternalSharing.ps1 @@ -43,6 +43,12 @@ function Test-RestrictExternalSharing { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-RestrictOutlookAddins.ps1 b/source/tests/Test-RestrictOutlookAddins.ps1 index 1cbcf34..6d28405 100644 --- a/source/tests/Test-RestrictOutlookAddins.ps1 +++ b/source/tests/Test-RestrictOutlookAddins.ps1 @@ -75,6 +75,12 @@ function Test-RestrictOutlookAddins { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 index 453b367..d6d5235 100644 --- a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 +++ b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 @@ -14,46 +14,52 @@ function Test-RestrictStorageProvidersOutlook { process { try { - # 6.5.3 (L2) Ensure additional storage providers are restricted in Outlook on the web + # 6.5.3 (L2) Ensure additional storage providers are restricted in Outlook on the web - # Retrieve all OwaMailbox policies - $owaPolicies = Get-OwaMailboxPolicy - $nonCompliantPolicies = $owaPolicies | Where-Object { $_.AdditionalStorageProvidersAvailable } + # Retrieve all OwaMailbox policies + $owaPolicies = Get-OwaMailboxPolicy + $nonCompliantPolicies = $owaPolicies | Where-Object { $_.AdditionalStorageProvidersAvailable } - # Determine compliance - $allPoliciesRestricted = $nonCompliantPolicies.Count -eq 0 + # Determine compliance + $allPoliciesRestricted = $nonCompliantPolicies.Count -eq 0 - # Prepare failure reasons and details based on compliance - $failureReasons = if ($allPoliciesRestricted) { - "N/A" - } - else { - "One or more OwaMailbox policies allow AdditionalStorageProvidersAvailable." + # Prepare failure reasons and details based on compliance + $failureReasons = if ($allPoliciesRestricted) { + "N/A" + } + else { + "One or more OwaMailbox policies allow AdditionalStorageProvidersAvailable." + } + + $details = if ($allPoliciesRestricted) { + "All OwaMailbox policies restrict AdditionalStorageProvidersAvailable" + } + else { + "Non-compliant OwaMailbox policies: $($nonCompliantPolicies.Name -join ', ')" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = $recnum + Result = $allPoliciesRestricted + Status = if ($allPoliciesRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $details = if ($allPoliciesRestricted) { - "All OwaMailbox policies restrict AdditionalStorageProvidersAvailable" - } - else { - "Non-compliant OwaMailbox policies: $($nonCompliantPolicies.Name -join ', ')" - } + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } - # Create and populate the CISAuditResult object - $params = @{ - Rec = $recnum - Result = $allPoliciesRestricted - Status = if ($allPoliciesRestricted) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons - } - $auditResult = Initialize-CISAuditResult @params - } - catch { - Write-Error "An error occurred during the test: $_" + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) - # Call Initialize-CISAuditResult with error parameters - $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure - } + # Call Initialize-CISAuditResult with error parameters + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { diff --git a/source/tests/Test-RestrictTenantCreation.ps1 b/source/tests/Test-RestrictTenantCreation.ps1 index 36107ae..be6a148 100644 --- a/source/tests/Test-RestrictTenantCreation.ps1 +++ b/source/tests/Test-RestrictTenantCreation.ps1 @@ -43,6 +43,12 @@ function Test-RestrictTenantCreation { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-SafeAttachmentsPolicy.ps1 b/source/tests/Test-SafeAttachmentsPolicy.ps1 index eafc7ff..3e5ad4f 100644 --- a/source/tests/Test-SafeAttachmentsPolicy.ps1 +++ b/source/tests/Test-SafeAttachmentsPolicy.ps1 @@ -48,6 +48,12 @@ function Test-SafeAttachmentsPolicy { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-SafeAttachmentsTeams.ps1 b/source/tests/Test-SafeAttachmentsTeams.ps1 index 1d9e32b..f87a437 100644 --- a/source/tests/Test-SafeAttachmentsTeams.ps1 +++ b/source/tests/Test-SafeAttachmentsTeams.ps1 @@ -55,6 +55,12 @@ function Test-SafeAttachmentsTeams { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-SafeLinksOfficeApps.ps1 b/source/tests/Test-SafeLinksOfficeApps.ps1 index 0660da2..0e1cfed 100644 --- a/source/tests/Test-SafeLinksOfficeApps.ps1 +++ b/source/tests/Test-SafeLinksOfficeApps.ps1 @@ -62,6 +62,12 @@ function Test-SafeLinksOfficeApps { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-SharePointAADB2B.ps1 b/source/tests/Test-SharePointAADB2B.ps1 index 7f1b6fb..7dfde4d 100644 --- a/source/tests/Test-SharePointAADB2B.ps1 +++ b/source/tests/Test-SharePointAADB2B.ps1 @@ -32,6 +32,12 @@ function Test-SharePointAADB2B { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-SharePointExternalSharingDomains.ps1 b/source/tests/Test-SharePointExternalSharingDomains.ps1 index f828ccf..848cba4 100644 --- a/source/tests/Test-SharePointExternalSharingDomains.ps1 +++ b/source/tests/Test-SharePointExternalSharingDomains.ps1 @@ -33,6 +33,12 @@ function Test-SharePointExternalSharingDomains { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-SharePointGuestsItemSharing.ps1 b/source/tests/Test-SharePointGuestsItemSharing.ps1 index 025951f..aade0b3 100644 --- a/source/tests/Test-SharePointGuestsItemSharing.ps1 +++ b/source/tests/Test-SharePointGuestsItemSharing.ps1 @@ -33,6 +33,12 @@ function Test-SharePointGuestsItemSharing { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-SpamPolicyAdminNotify.ps1 b/source/tests/Test-SpamPolicyAdminNotify.ps1 index aa2b181..8bb73bc 100644 --- a/source/tests/Test-SpamPolicyAdminNotify.ps1 +++ b/source/tests/Test-SpamPolicyAdminNotify.ps1 @@ -48,6 +48,12 @@ function Test-SpamPolicyAdminNotify { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-TeamsExternalAccess.ps1 b/source/tests/Test-TeamsExternalAccess.ps1 index c4ee735..059cdf7 100644 --- a/source/tests/Test-TeamsExternalAccess.ps1 +++ b/source/tests/Test-TeamsExternalAccess.ps1 @@ -43,6 +43,12 @@ function Test-TeamsExternalAccess { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/source/tests/Test-TeamsExternalFileSharing.ps1 b/source/tests/Test-TeamsExternalFileSharing.ps1 index 1d5a135..4004dcc 100644 --- a/source/tests/Test-TeamsExternalFileSharing.ps1 +++ b/source/tests/Test-TeamsExternalFileSharing.ps1 @@ -47,6 +47,12 @@ function Test-TeamsExternalFileSharing { catch { Write-Error "An error occurred during the test: $_" + # Retrieve the description from the test definitions + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } diff --git a/tests/Unit/Private/Invoke-TestFunction.tests.ps1 b/tests/Unit/Private/Invoke-TestFunction.tests.ps1 new file mode 100644 index 0000000..4a2aa69 --- /dev/null +++ b/tests/Unit/Private/Invoke-TestFunction.tests.ps1 @@ -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' + } + } + } +} + diff --git a/tests/Unit/Private/Measure-AuditResult.tests.ps1 b/tests/Unit/Private/Measure-AuditResult.tests.ps1 new file mode 100644 index 0000000..4a2aa69 --- /dev/null +++ b/tests/Unit/Private/Measure-AuditResult.tests.ps1 @@ -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' + } + } + } +} + From cb52ce1a73f0a996526739fbf4af5e6f3a90a668 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:43:02 -0500 Subject: [PATCH 08/45] docs: update CHANGELOG --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 546b8f7..9baef64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,13 @@ The format is based on and uses the types of changes according to [Keep a Change - Updated test definitions for CIS Microsoft 365 Foundations Benchmark for better error handling and object output when errors occur. - Added a parameter to the `Initialize-CISAuditResult` function to allow for a static failed object to be created when an error occurs. +- Refactored `Invoke-M365SecurityAudit` to include a new private function `Invoke-TestFunction` for executing test functions and handling errors. +- Added a new private function `Measure-AuditResult` to calculate and display audit results. +- Enhanced error logging to capture failed test details and display them at the end of the audit. ### Fixed - +- Ensured the `Invoke-TestFunction` returns a `CISAuditResult` object, which is then managed in the `Invoke-M365SecurityAudit` function. ## [0.1.4] - 2024-05-30 @@ -98,4 +101,4 @@ The format is based on and uses the types of changes according to [Keep a Change - A dynamic test loading system based on CSV input for flexibility in defining audit tests. - Comprehensive verbose logging to detail the steps being performed during an audit. - Comment-help documentation for the `Invoke-M365SecurityAudit` function with examples and usage details. -- Attribution to CIS and licensing information under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License in the README. \ No newline at end of file +- Attribution to CIS and licensing information under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License in the README. From 92e5952f7eb6ea2b376a0f9e1f92c8f20a316363 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:40:18 -0500 Subject: [PATCH 09/45] Add: Module function --- source/Private/Get-RequiredModule.ps1 | 15 ++++++++++ source/Public/Invoke-M365SecurityAudit.ps1 | 28 +++---------------- .../Unit/Private/Get-RequiredModule.tests.ps1 | 27 ++++++++++++++++++ 3 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 source/Private/Get-RequiredModule.ps1 create mode 100644 tests/Unit/Private/Get-RequiredModule.tests.ps1 diff --git a/source/Private/Get-RequiredModule.ps1 b/source/Private/Get-RequiredModule.ps1 new file mode 100644 index 0000000..fb426f5 --- /dev/null +++ b/source/Private/Get-RequiredModule.ps1 @@ -0,0 +1,15 @@ +function Get-RequiredModule { + return @( + @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0" }, + @{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182" }, + @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Authentication" }, + @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Users" }, + @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Groups" }, + @{ 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" } + ) +} diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index 682bfdd..dc9f15c 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -65,24 +65,11 @@ function Invoke-M365SecurityAudit { } # Ensure required modules are installed if (!($NoModuleCheck)) { - $requiredModules = @( - @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0" }, - @{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Authentication" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Users" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Groups" }, - @{ 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" } - ) + $requiredModules = Get-RequiredModule foreach ($module in $requiredModules) { Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName } } - # Load test definitions from CSV $testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath "helper\TestDefinitions.csv" $testDefinitions = Import-Csv -Path $testDefinitionsPath @@ -99,39 +86,33 @@ function Invoke-M365SecurityAudit { SkipRecommendation = $SkipRecommendation } $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 } - # Determine which test files to load based on filtering $testsToLoad = $testDefinitions.TestFileName | ForEach-Object { $_ -replace '.ps1$', '' } - Write-Verbose "The $(($testsToLoad).count) test/s that would be loaded based on filter criteria:" $testsToLoad | ForEach-Object { Write-Verbose " $_" } - # 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 $testsFolderPath = Join-Path -Path $PSScriptRoot -ChildPath "tests" $testFiles = Get-ChildItem -Path $testsFolderPath -Filter "Test-*.ps1" | Where-Object { $testsToLoad -contains $_.BaseName } - # Import the test functions $testFiles | ForEach-Object { Try { + # Dot source the test function . $_.FullName } Catch { + # Log the error and add the test to the failed tests collection Write-Error "Failed to load test function $($_.Name): $_" $script:FailedTests.Add([PSCustomObject]@{ Test = $_.Name; Error = $_ }) } @@ -142,6 +123,7 @@ function Invoke-M365SecurityAudit { $functionName = $testFunction.BaseName if ($PSCmdlet.ShouldProcess($functionName, "Execute test")) { $auditResult = Invoke-TestFunction -FunctionFile $testFunction -DomainName $DomainName + # Add the result to the collection [void]$allAuditResults.Add($auditResult) } } @@ -152,10 +134,8 @@ function Invoke-M365SecurityAudit { # Clean up sessions Disconnect-M365Suite -RequiredConnections $requiredConnections } - # Call the private function to calculate and display results Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests - # Return all collected audit results return $allAuditResults.ToArray() } diff --git a/tests/Unit/Private/Get-RequiredModule.tests.ps1 b/tests/Unit/Private/Get-RequiredModule.tests.ps1 new file mode 100644 index 0000000..4a2aa69 --- /dev/null +++ b/tests/Unit/Private/Get-RequiredModule.tests.ps1 @@ -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' + } + } + } +} + From 4857aead5e5ee9528a22c99ca5c3e8879de75074 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:56:58 -0500 Subject: [PATCH 10/45] docs: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9baef64..802522e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on and uses the types of changes according to [Keep a Change - Refactored `Invoke-M365SecurityAudit` to include a new private function `Invoke-TestFunction` for executing test functions and handling errors. - Added a new private function `Measure-AuditResult` to calculate and display audit results. - Enhanced error logging to capture failed test details and display them at the end of the audit. +- Added a private function `Get-RequiredModule` to initialize the `$requiredModules` variable for better code organization in the main script. ### Fixed From d9ed3b60b7b98670eae7446acef6eb8fd2a84507 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 10:31:38 -0500 Subject: [PATCH 11/45] fix: output in 6.1.2,6.1.3 update changelog --- source/Private/Format-MissingActions.ps1 | 11 +++++------ source/tests/Test-MailboxAuditingE3.ps1 | 17 +++++++++-------- source/tests/Test-MailboxAuditingE5.ps1 | 19 +++++++++---------- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/source/Private/Format-MissingActions.ps1 b/source/Private/Format-MissingActions.ps1 index b9efa97..f6fd0bf 100644 --- a/source/Private/Format-MissingActions.ps1 +++ b/source/Private/Format-MissingActions.ps1 @@ -15,12 +15,11 @@ function Format-MissingActions { } } - $formattedResults = @() - foreach ($type in $actionGroups.Keys) { - if ($actionGroups[$type].Count -gt 0) { - $formattedResults += "$($type) actions missing: $($actionGroups[$type] -join ', ')" - } + $formattedResults = @{ + Admin = $actionGroups["Admin"] -join ', ' + Delegate = $actionGroups["Delegate"] -join ', ' + Owner = $actionGroups["Owner"] -join ', ' } - return $formattedResults -join '; ' + return $formattedResults } \ No newline at end of file diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index fb9e129..9bb5e19 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -1,8 +1,6 @@ function Test-MailboxAuditingE3 { [CmdletBinding()] param ( - # Aligned - # Create Table for Details # Parameters can be added if needed ) @@ -15,7 +13,6 @@ function Test-MailboxAuditingE3 { $DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules") $OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MoveToDeletedItems", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") - $allFailures = @() $allUsers = Get-AzureADUser -All $true $processedUsers = @{} # Dictionary to track processed users @@ -51,13 +48,13 @@ function Test-MailboxAuditingE3 { } } else { - $allFailures += "$userUPN`: AuditEnabled - False" + $allFailures += "$userUPN|False|||" continue } if ($missingActions) { - $formattedActions = Format-MissingActions $missingActions - $allFailures += "$userUPN`: AuditEnabled - True; $formattedActions" + $formattedActions = Format-MissingActions -missingActions $missingActions + $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" } # Mark the user as processed $processedUsers[$user.UserPrincipalName] = $true @@ -66,7 +63,12 @@ function Test-MailboxAuditingE3 { # Prepare failure reasons and details based on compliance $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } - $details = if ($allFailures.Count -eq 0) { "All Office E3 users have correct mailbox audit settings." } else { $allFailures -join " | " } + $details = if ($allFailures.Count -eq 0) { + "All Office E3 users have correct mailbox audit settings." + } + else { + "UserPrincipalName|AuditEnabled|AdminActionsMissing|DelegateActionsMissing|OwnerActionsMissing`n" + ($allFailures -join "`n") + } # Populate the audit result $params = @{ @@ -77,7 +79,6 @@ function Test-MailboxAuditingE3 { FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params - } catch { Write-Error "An error occurred during the test: $_" diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index df8f145..978ffa2 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -1,8 +1,6 @@ function Test-MailboxAuditingE5 { [CmdletBinding()] param ( - # Aligned - # Create Table for Details # Parameters can be added if needed ) @@ -15,8 +13,6 @@ function Test-MailboxAuditingE5 { $DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules") $OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MailItemsAccessed", "MoveToDeletedItems", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") - - $allFailures = @() $allUsers = Get-AzureADUser -All $true $processedUsers = @{} # Dictionary to track processed users @@ -30,10 +26,10 @@ function Test-MailboxAuditingE5 { continue } - $licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName $hasOfficeE5 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e5SkuPartNumbers }).Count -gt 0 Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E5 license." + if ($hasOfficeE5) { $userUPN = $user.UserPrincipalName $mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit @@ -51,13 +47,13 @@ function Test-MailboxAuditingE5 { } } else { - $allFailures += "$userUPN`: AuditEnabled - False" + $allFailures += "$userUPN|False|||" continue } if ($missingActions) { - $formattedActions = Format-MissingActions $missingActions - $allFailures += "$userUPN`: AuditEnabled - True; $formattedActions" + $formattedActions = Format-MissingActions -missingActions $missingActions + $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" } else { Write-Verbose "User $($user.UserPrincipalName) passed the mailbox audit checks." @@ -68,12 +64,15 @@ function Test-MailboxAuditingE5 { # Adding verbose output to indicate the user does not have an E5 license Write-Verbose "User $($user.UserPrincipalName) does not have an Office E5 license." } - } # Prepare failure reasons and details based on compliance $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } - $details = if ($allFailures.Count -eq 0) { "All Office E5 users have correct mailbox audit settings." } else { $allFailures -join " | " } + $details = if ($allFailures.Count -eq 0) { + "All Office E5 users have correct mailbox audit settings." + } else { + "UserPrincipalName|AuditEnabled|AdminActionsMissing|DelegateActionsMissing|OwnerActionsMissing`n" + ($allFailures -join "`n") + } # Populate the audit result $params = @{ From f5ab68dd63f15696e67e6313616757ff17ccc8da Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 13:04:33 -0500 Subject: [PATCH 12/45] fix: output in 6.2.1 so joine won't fail --- source/tests/Test-BlockMailForwarding.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index dbe539a..9435a87 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -1,7 +1,6 @@ function Test-BlockMailForwarding { [CmdletBinding()] param ( - # Aligned Compare # Parameters can be added if needed ) @@ -30,7 +29,7 @@ function Test-BlockMailForwarding { $details = if ($transportRules.Count -gt 0) { $transportRules | ForEach-Object { - "$($_.Name) redirects to $($_.RedirectMessageTo)" + "$($_.Name) redirects to $($_.RedirectMessageTo -join ', ')" } -join " | " } else { From c530d2df76689268b123486d0957e78e8db1955e Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 13:39:12 -0500 Subject: [PATCH 13/45] docs: Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 802522e..d9d0d7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,13 @@ The format is based on and uses the types of changes according to [Keep a Change - Added a new private function `Measure-AuditResult` to calculate and display audit results. - Enhanced error logging to capture failed test details and display them at the end of the audit. - Added a private function `Get-RequiredModule` to initialize the `$requiredModules` variable for better code organization in the main script. +- Updated `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` functions to use `Format-MissingActions` for structuring missing actions into a pipe-separated table format. +- Added more verbose logging to `Test-BlockMailForwarding` and improved error handling for better troubleshooting. ### Fixed - Ensured the `Invoke-TestFunction` returns a `CISAuditResult` object, which is then managed in the `Invoke-M365SecurityAudit` function. +- Corrected the usage of the join operation within `$details` in `Test-BlockMailForwarding` to handle arrays properly. ## [0.1.4] - 2024-05-30 From 8de61dda9f884d4f7a709ff1cf3b2bf03bfe57d4 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:15:57 -0500 Subject: [PATCH 14/45] fix: 7.3.4 so it outputs a pipe separated table --- source/tests/Test-RestrictCustomScripts.ps1 | 23 +++++++++------------ 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 5bc6f6c..c0c3170 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -1,7 +1,6 @@ function Test-RestrictCustomScripts { [CmdletBinding()] param ( - # Aligned # Define your parameters here if needed ) @@ -25,24 +24,22 @@ function Test-RestrictCustomScripts { # Compliance is true if no sites allow custom scripts $complianceResult = $customScriptAllowedSites.Count -eq 0 - # Gather details for non-compliant sites (where custom scripts are allowed) - $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { - "$($_.Title) ($($_.Url)): Custom Script Allowed" - } - # Prepare failure reasons and details based on compliance - $failureReasons = if (-not $complianceResult) { - "The following site collections allow custom script execution: " + ($nonCompliantSiteDetails -join "; ") - } - else { + $failureReasons = if ($complianceResult) { "N/A" + } else { + "The following site collections allow custom script execution:" } $details = if ($complianceResult) { "All site collections have custom script execution restricted" - } - else { - $nonCompliantSiteDetails -join "; " + } else { + # Create pipe-separated table for non-compliant sites + $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { + $title = if ($_.Title) { $_.Title } else { "No Title" } + "$title|$($_.Url)|True" + } + "Title|Url|CustomScriptAllowed`n" + ($nonCompliantSiteDetails -join "`n") } # Create and populate the CISAuditResult object From 85bd0fb19f35d2dcb94f93a2ed90412cdf6ef295 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:06:47 -0500 Subject: [PATCH 15/45] add: sort to output --- source/Public/Invoke-M365SecurityAudit.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index dc9f15c..1b7632c 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -137,6 +137,6 @@ function Invoke-M365SecurityAudit { # Call the private function to calculate and display results Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests # Return all collected audit results - return $allAuditResults.ToArray() + return $allAuditResults.ToArray() | Sort-Object -Property Rec } } From c6bdad0477a5d05fe84e773e6f5ac4ee0cdb5a18 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:07:36 -0500 Subject: [PATCH 16/45] fix: improve output of 6.1.2 --- source/tests/Test-MailboxAuditingE3.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index 9bb5e19..c103d23 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -46,16 +46,16 @@ function Test-MailboxAuditingE3 { foreach ($action in $OwnerActions) { if ($mailbox.AuditOwner -notcontains $action) { $missingActions += "Owner action '$action' missing" } } + + if ($missingActions.Count -gt 0) { + $formattedActions = Format-MissingActions -missingActions $missingActions + $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" + } } else { $allFailures += "$userUPN|False|||" - continue } - if ($missingActions) { - $formattedActions = Format-MissingActions -missingActions $missingActions - $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" - } # Mark the user as processed $processedUsers[$user.UserPrincipalName] = $true } From 8922ea12cd96058d8008d9f4d2e6966fd1124e44 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:08:15 -0500 Subject: [PATCH 17/45] fix: improve output of 7.3.4 --- source/tests/Test-RestrictCustomScripts.ps1 | 49 +++++++++++++-------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index c0c3170..e1ad809 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -6,49 +6,62 @@ function Test-RestrictCustomScripts { begin { # Dot source the class script if necessary - #. .\source\Classes\CISAuditResult.ps1 + # . .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $recnum = "7.3.4" } process { + try { # 7.3.4 (L1) Ensure custom script execution is restricted on site collections # Retrieve all site collections and select necessary properties $SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages - # Find sites where custom scripts are allowed (DenyAddAndCustomizePages is not 'Enabled') - $customScriptAllowedSites = $SPOSitesCustomScript | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } + # Replace 'sharepoint.com' with '' + $processedUrls = $SPOSitesCustomScript | ForEach-Object { + $_.Url = $_.Url -replace 'sharepoint\.com', '' + $_ + } + + # Extract hostnames and find the most used one + $hostnames = $processedUrls.Url | ForEach-Object { $_ -match '^https://([^\.]+)\.' | Out-Null; $matches[1] } + $mostUsedHostname = $hostnames | Group-Object | Sort-Object Count -Descending | Select-Object -First 1 -ExpandProperty Name # Compliance is true if no sites allow custom scripts + $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } $complianceResult = $customScriptAllowedSites.Count -eq 0 + # Gather details for non-compliant sites (where custom scripts are allowed) + $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { + $url = $_.Url -replace [regex]::Escape($mostUsedHostname), "" + "$(if ($_.Title) {$_.Title} else {"NoTitle"})|$url|$true" + } + # Prepare failure reasons and details based on compliance - $failureReasons = if ($complianceResult) { + $failureReasons = if (-not $complianceResult) { + "Title|Url|CustomScriptAllowed`n" + ($nonCompliantSiteDetails -join "`n") + } + else { "N/A" - } else { - "The following site collections allow custom script execution:" } $details = if ($complianceResult) { "All site collections have custom script execution restricted" - } else { - # Create pipe-separated table for non-compliant sites - $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { - $title = if ($_.Title) { $_.Title } else { "No Title" } - "$title|$($_.Url)|True" - } - "Title|Url|CustomScriptAllowed`n" + ($nonCompliantSiteDetails -join "`n") + } + else { + "Some site collections are not restricting custom script execution. Review FailureReason property for sites that are not aligned with the benchmark." } # Create and populate the CISAuditResult object $params = @{ - Rec = $recnum - Result = $complianceResult - Status = if ($complianceResult) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + Rec = $recnum + Result = $complianceResult + Status = if ($complianceResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params } From 8719900af7d005fc3a2bcabccb8a309262754534 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:49:37 -0500 Subject: [PATCH 18/45] test: testingoutput --- source/Private/Get-MostCommonWord.ps1 | 22 +++++++++ source/tests/Test-RestrictCustomScripts.ps1 | 53 +++++++++++++++------ 2 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 source/Private/Get-MostCommonWord.ps1 diff --git a/source/Private/Get-MostCommonWord.ps1 b/source/Private/Get-MostCommonWord.ps1 new file mode 100644 index 0000000..b626b5e --- /dev/null +++ b/source/Private/Get-MostCommonWord.ps1 @@ -0,0 +1,22 @@ +function Get-MostCommonWord { + param ( + [Parameter(Mandatory = $true)] + [string[]]$InputStrings + ) + + # Combine all strings into one large string + $allText = $InputStrings -join ' ' + + # Split the large string into words + $words = $allText -split '\s+' + + # Group words and count occurrences + $wordGroups = $words | Group-Object | Sort-Object Count -Descending + + # Return the most common word if it occurs at least 3 times + if ($wordGroups.Count -gt 0 -and $wordGroups[0].Count -ge 3) { + return $wordGroups[0].Name + } else { + return $null + } +} \ No newline at end of file diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index e1ad809..5dbd411 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -20,29 +20,43 @@ function Test-RestrictCustomScripts { # Retrieve all site collections and select necessary properties $SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages - # Replace 'sharepoint.com' with '' + # Replace 'sharepoint.com' with '' $processedUrls = $SPOSitesCustomScript | ForEach-Object { - $_.Url = $_.Url -replace 'sharepoint\.com', '' + $_.Url = $_.Url -replace 'sharepoint\.com', '' $_ } - # Extract hostnames and find the most used one - $hostnames = $processedUrls.Url | ForEach-Object { $_ -match '^https://([^\.]+)\.' | Out-Null; $matches[1] } - $mostUsedHostname = $hostnames | Group-Object | Sort-Object Count -Descending | Select-Object -First 1 -ExpandProperty Name + # Find sites where custom scripts are allowed + $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } + + # Extract hostnames from allowed sites + Write-Verbose "Extracting hostnames from URLs..." + $hostnames = $customScriptAllowedSites.Url | ForEach-Object { + if ($_ -match '^https://([^\.]+)\.') { + $matches[1] + } + } + Write-Verbose "Extracted hostnames: $($hostnames -join ', ')" + + # Find the most used hostname using the Get-MostCommonWord function + $mostUsedHostname = Get-MostCommonWord -InputStrings $hostnames + Write-Verbose "Most used hostname: $mostUsedHostname" # Compliance is true if no sites allow custom scripts - $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } $complianceResult = $customScriptAllowedSites.Count -eq 0 # Gather details for non-compliant sites (where custom scripts are allowed) $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { - $url = $_.Url -replace [regex]::Escape($mostUsedHostname), "" - "$(if ($_.Title) {$_.Title} else {"NoTitle"})|$url|$true" + $url = $_.Url + if ($null -ne $mostUsedHostname -and $url -match "^https://$mostUsedHostname\.") { + $url = $url -replace "^https://$mostUsedHostname\.", "https://." + } + "$(if ($_.Title) {$_.Title} else {"NoTitle"})|$url" } # Prepare failure reasons and details based on compliance $failureReasons = if (-not $complianceResult) { - "Title|Url|CustomScriptAllowed`n" + ($nonCompliantSiteDetails -join "`n") + "Some site collections are not restricting custom script execution. Review Details property for sites that are not aligned with the benchmark." } else { "N/A" @@ -52,16 +66,16 @@ function Test-RestrictCustomScripts { "All site collections have custom script execution restricted" } else { - "Some site collections are not restricting custom script execution. Review FailureReason property for sites that are not aligned with the benchmark." + "Title|Url`n" + ($nonCompliantSiteDetails -join "`n") } # Create and populate the CISAuditResult object $params = @{ - Rec = $recnum - Result = $complianceResult - Status = if ($complianceResult) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + Rec = $recnum + Result = $complianceResult + Status = if ($complianceResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params } @@ -80,6 +94,15 @@ function Test-RestrictCustomScripts { } end { + # Measure the character count of the details + $verbosePreference = 'Continue' + $detailsLength = $details.Length + Write-Verbose "Character count of the details: $detailsLength" + + if ($detailsLength -gt 32767) { + Write-Verbose "Warning: The character count exceeds the limit for Excel cells." + } + $verbosePreference = 'SilentlyContinue' # Return auditResult return $auditResult } From f905f269d1d3f3dd2308780809386d28b7f3b0a3 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 21:10:28 -0500 Subject: [PATCH 19/45] fix: output for 6.1.2/3 and 7.3.4 --- source/tests/Test-MailboxAuditingE3.ps1 | 8 +++++ source/tests/Test-MailboxAuditingE5.ps1 | 30 +++++++++++-------- source/tests/Test-RestrictCustomScripts.ps1 | 29 +++++++++++------- .../Unit/Private/Get-MostCommonWord.tests.ps1 | 27 +++++++++++++++++ 4 files changed, 70 insertions(+), 24 deletions(-) create mode 100644 tests/Unit/Private/Get-MostCommonWord.tests.ps1 diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index c103d23..ad6364b 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -95,6 +95,14 @@ function Test-MailboxAuditingE3 { } end { + #$verbosePreference = 'Continue' + $detailsLength = $details.Length + Write-Verbose "Character count of the details: $detailsLength" + + if ($detailsLength -gt 32767) { + Write-Verbose "Warning: The character count exceeds the limit for Excel cells." + } + #$verbosePreference = 'SilentlyContinue' return $auditResult } } diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index 978ffa2..539b628 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -23,6 +23,7 @@ function Test-MailboxAuditingE5 { try { foreach ($user in $allUsers) { if ($processedUsers.ContainsKey($user.UserPrincipalName)) { + Write-Verbose "Skipping already processed user: $($user.UserPrincipalName)" continue } @@ -45,32 +46,27 @@ function Test-MailboxAuditingE5 { foreach ($action in $OwnerActions) { if ($mailbox.AuditOwner -notcontains $action) { $missingActions += "Owner action '$action' missing" } } + + if ($missingActions.Count -gt 0) { + $formattedActions = Format-MissingActions -missingActions $missingActions + $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" + } } else { $allFailures += "$userUPN|False|||" - continue } - if ($missingActions) { - $formattedActions = Format-MissingActions -missingActions $missingActions - $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" - } - else { - Write-Verbose "User $($user.UserPrincipalName) passed the mailbox audit checks." - } + # Mark the user as processed $processedUsers[$user.UserPrincipalName] = $true } - else { - # Adding verbose output to indicate the user does not have an E5 license - Write-Verbose "User $($user.UserPrincipalName) does not have an Office E5 license." - } } # Prepare failure reasons and details based on compliance $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } $details = if ($allFailures.Count -eq 0) { "All Office E5 users have correct mailbox audit settings." - } else { + } + else { "UserPrincipalName|AuditEnabled|AdminActionsMissing|DelegateActionsMissing|OwnerActionsMissing`n" + ($allFailures -join "`n") } @@ -99,6 +95,14 @@ function Test-MailboxAuditingE5 { } end { + #$verbosePreference = 'Continue' + $detailsLength = $details.Length + Write-Verbose "Character count of the details: $detailsLength" + + if ($detailsLength -gt 32767) { + Write-Verbose "Warning: The character count exceeds the limit for Excel cells." + } + #$verbosePreference = 'SilentlyContinue' return $auditResult } } diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 5dbd411..9eb39e7 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -28,20 +28,27 @@ function Test-RestrictCustomScripts { # Find sites where custom scripts are allowed $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } + $verbosePreference = 'Continue' + # Check the total length of URLs + $totalUrlLength = ($customScriptAllowedSites.Url -join '').Length + Write-Verbose "Total length of URLs: $totalUrlLength" - # Extract hostnames from allowed sites - Write-Verbose "Extracting hostnames from URLs..." - $hostnames = $customScriptAllowedSites.Url | ForEach-Object { - if ($_ -match '^https://([^\.]+)\.') { - $matches[1] + # Extract hostnames from allowed sites if the total length exceeds the limit + $mostUsedHostname = $null + if ($totalUrlLength -gt 20000) { + Write-Verbose "Extracting hostnames from URLs..." + $hostnames = $customScriptAllowedSites.Url | ForEach-Object { + if ($_ -match '^https://([^\.]+)\.') { + $matches[1] + } } + Write-Verbose "Extracted hostnames: $($hostnames -join ', ')" + + # Find the most used hostname using the Get-MostCommonWord function + $mostUsedHostname = Get-MostCommonWord -InputStrings $hostnames + Write-Verbose "Most used hostname: $mostUsedHostname" } - Write-Verbose "Extracted hostnames: $($hostnames -join ', ')" - - # Find the most used hostname using the Get-MostCommonWord function - $mostUsedHostname = Get-MostCommonWord -InputStrings $hostnames - Write-Verbose "Most used hostname: $mostUsedHostname" - + $verbosePreference = 'SilentlyContinue' # Compliance is true if no sites allow custom scripts $complianceResult = $customScriptAllowedSites.Count -eq 0 diff --git a/tests/Unit/Private/Get-MostCommonWord.tests.ps1 b/tests/Unit/Private/Get-MostCommonWord.tests.ps1 new file mode 100644 index 0000000..4a2aa69 --- /dev/null +++ b/tests/Unit/Private/Get-MostCommonWord.tests.ps1 @@ -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' + } + } + } +} + From f47efa74f963e58caed874b8afe402854af416a3 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 21:20:24 -0500 Subject: [PATCH 20/45] docs: Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9d0d7c..4f722e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,11 +14,14 @@ The format is based on and uses the types of changes according to [Keep a Change - Added a private function `Get-RequiredModule` to initialize the `$requiredModules` variable for better code organization in the main script. - Updated `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` functions to use `Format-MissingActions` for structuring missing actions into a pipe-separated table format. - Added more verbose logging to `Test-BlockMailForwarding` and improved error handling for better troubleshooting. +- Improved `Test-RestrictCustomScripts` to handle long URL lengths better by extracting and replacing common hostnames, and provided detailed output. ### Fixed - Ensured the `Invoke-TestFunction` returns a `CISAuditResult` object, which is then managed in the `Invoke-M365SecurityAudit` function. - Corrected the usage of the join operation within `$details` in `Test-BlockMailForwarding` to handle arrays properly. +- Fixed the logic in `Test-RestrictCustomScripts` to accurately replace and manage URLs, ensuring compliance checks are correctly performed. +- Updated the `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` functions to handle the `$allFailures` variable correctly, ensuring accurate pass/fail results. ## [0.1.4] - 2024-05-30 From d85968935b5e580f150804b0301a1f73e484aaf0 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Fri, 7 Jun 2024 21:37:28 -0500 Subject: [PATCH 21/45] fix: remove verbose preference from 7.3.4 --- source/tests/Test-RestrictCustomScripts.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 9eb39e7..34017ca 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -28,7 +28,7 @@ function Test-RestrictCustomScripts { # Find sites where custom scripts are allowed $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } - $verbosePreference = 'Continue' + #$verbosePreference = 'Continue' # Check the total length of URLs $totalUrlLength = ($customScriptAllowedSites.Url -join '').Length Write-Verbose "Total length of URLs: $totalUrlLength" @@ -48,7 +48,7 @@ function Test-RestrictCustomScripts { $mostUsedHostname = Get-MostCommonWord -InputStrings $hostnames Write-Verbose "Most used hostname: $mostUsedHostname" } - $verbosePreference = 'SilentlyContinue' + #$verbosePreference = 'SilentlyContinue' # Compliance is true if no sites allow custom scripts $complianceResult = $customScriptAllowedSites.Count -eq 0 @@ -102,14 +102,14 @@ function Test-RestrictCustomScripts { end { # Measure the character count of the details - $verbosePreference = 'Continue' + #$verbosePreference = 'Continue' $detailsLength = $details.Length Write-Verbose "Character count of the details: $detailsLength" if ($detailsLength -gt 32767) { Write-Verbose "Warning: The character count exceeds the limit for Excel cells." } - $verbosePreference = 'SilentlyContinue' + #$verbosePreference = 'SilentlyContinue' # Return auditResult return $auditResult } From e0e2a04b6a9165ea73138b74c67c3630624eba86 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 09:13:46 -0500 Subject: [PATCH 22/45] fix: add check for length in 7.3.4 details. --- source/tests/Test-RestrictCustomScripts.ps1 | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 34017ca..99daa5a 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -20,9 +20,9 @@ function Test-RestrictCustomScripts { # Retrieve all site collections and select necessary properties $SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages - # Replace 'sharepoint.com' with '' + # Replace 'sharepoint.com' with '' $processedUrls = $SPOSitesCustomScript | ForEach-Object { - $_.Url = $_.Url -replace 'sharepoint\.com', '' + $_.Url = $_.Url -replace 'sharepoint\.com', '' $_ } @@ -55,8 +55,8 @@ function Test-RestrictCustomScripts { # Gather details for non-compliant sites (where custom scripts are allowed) $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { $url = $_.Url - if ($null -ne $mostUsedHostname -and $url -match "^https://$mostUsedHostname\.") { - $url = $url -replace "^https://$mostUsedHostname\.", "https://." + if ($null -ne $mostUsedHostname -and $url -match "^https://$mostUsedHostname\.") { + $url = $url -replace "^https://$mostUsedHostname\.", "https://." } "$(if ($_.Title) {$_.Title} else {"NoTitle"})|$url" } @@ -76,6 +76,16 @@ function Test-RestrictCustomScripts { "Title|Url`n" + ($nonCompliantSiteDetails -join "`n") } + # Convert details to PSObject and check length + $detailsPSObject = $details | ConvertFrom-Csv -Delimiter '|' + $detailsLength = ($detailsPSObject | ForEach-Object { $_.Url }).Length + + if ($detailsLength -gt 32767) { + # Create a preview of the first 10 results + $preview = $detailsPSObject | Select-Object -First 10 | ForEach-Object { "$($_.Title)|$($_.Url)" } + $details = "The output is too large. Here is a preview of the first 10 results:`n`n" + ($preview -join "`n") + "`n`nPlease run the test with the following commands to get the full details:`n`nGet-SPOSite -Limit All | Where-Object { `$.DenyAddAndCustomizePages -ne 'Enabled' } | Select-Object Title, Url" + } + # Create and populate the CISAuditResult object $params = @{ Rec = $recnum From 6495073a10776fe1666082f85e9e419be2012185 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 10:39:29 -0500 Subject: [PATCH 23/45] fix: step 1 and step 2 in 6.2.1 details. --- source/tests/Test-BlockMailForwarding.ps1 | 51 ++++++++++++++++------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index 9435a87..692dda2 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -15,27 +15,50 @@ function Test-BlockMailForwarding { try { # 6.2.1 (L1) Ensure all forms of mail forwarding are blocked and/or disabled - # Retrieve the transport rules that redirect messages + # Step 1: Retrieve the transport rules that redirect messages $transportRules = Get-TransportRule | Where-Object { $null -ne $_.RedirectMessageTo } - $forwardingBlocked = $transportRules.Count -eq 0 + $transportForwardingBlocked = $transportRules.Count -eq 0 + + # Step 2: Check all anti-spam outbound policies + $outboundSpamPolicies = Get-HostedOutboundSpamFilterPolicy + $nonCompliantSpamPolicies = $outboundSpamPolicies | Where-Object { $_.AutoForwardingMode -ne 'Off' } + $nonCompliantSpamPoliciesArray = @($nonCompliantSpamPolicies) + $spamForwardingBlocked = $nonCompliantSpamPoliciesArray.Count -eq 0 + + # Determine overall compliance + $forwardingBlocked = $transportForwardingBlocked -and $spamForwardingBlocked # Prepare failure reasons and details based on compliance - $failureReasons = if ($transportRules.Count -gt 0) { - "Mail forwarding rules found: $($transportRules.Name -join ', ')" - } - else { - "N/A" + $failureReasons = @() + $details = @() + + if ($transportRules.Count -gt 0) { + $failureReasons += "Mail forwarding rules found: $($transportRules.Name -join ', ')" + $details += "Transport Rules Details:`nRule Name|Redirects To" + $details += $transportRules | ForEach-Object { + "$($_.Name)|$($_.RedirectMessageTo -join ', ')" + } + $details += "`n" } - $details = if ($transportRules.Count -gt 0) { - $transportRules | ForEach-Object { - "$($_.Name) redirects to $($_.RedirectMessageTo -join ', ')" - } -join " | " - } - else { - "Step 1: No forwarding rules found. Please proceed with Step 2 described in CIS Benchmark." + if ($nonCompliantSpamPoliciesArray.Count -gt 0) { + $failureReasons += "Outbound spam policies allowing automatic forwarding found." + $details += "Outbound Spam Policies Details:`nPolicy|AutoForwardingMode" + $details += $nonCompliantSpamPoliciesArray | ForEach-Object { + "$($_.Name)|$($_.AutoForwardingMode)" + } } + if ($failureReasons.Count -eq 0) { + $failureReasons = "N/A" + $details = "Both transport rules and outbound spam policies are configured correctly to block forwarding." + } + else { + $failureReasons = $failureReasons -join " | " + $details = $details -join "`n" + } + + # Populate the audit result $params = @{ Rec = $recnum Result = $forwardingBlocked From b9a8a75945c42bfdcd594ba88ef9c405eeb0f237 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:20:02 -0500 Subject: [PATCH 24/45] fix: minimized mggraph call count and adjusted output in 1.1.1 --- .../Test-AdministrativeAccountCompliance.ps1 | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index ff1aeee..1b22bdb 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -1,27 +1,43 @@ function Test-AdministrativeAccountCompliance { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) begin { - # Initialize the valid licenses $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') $recnum = "1.1.1" } process { try { + # Retrieve all necessary data outside the loops $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } + $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment + $principalIds = $roleAssignments.PrincipalId | Select-Object -Unique + + # Fetch user details using filter + $userDetailsList = @{} + $licensesList = @{} + + $userDetails = Get-MgUser -Filter "id in ('$($principalIds -join "','")')" -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue + foreach ($user in $userDetails) { + $userDetailsList[$user.Id] = $user + } + + # Fetch user licenses for each unique principal ID + foreach ($principalId in $principalIds) { + $licensesList[$principalId] = Get-MgUserLicenseDetail -UserId $principalId -ErrorAction SilentlyContinue + } + $adminRoleUsers = @() foreach ($role in $adminRoles) { - $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" - - foreach ($assignment in $roleAssignments) { - $userDetails = Get-MgUser -UserId $assignment.PrincipalId -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue + foreach ($assignment in $roleAssignments | Where-Object { $_.RoleDefinitionId -eq $role.Id }) { + $userDetails = $userDetailsList[$assignment.PrincipalId] if ($userDetails) { - $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue + $licenses = $licensesList[$assignment.PrincipalId] $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } $adminRoleUsers += [PSCustomObject]@{ @@ -51,21 +67,25 @@ function Test-AdministrativeAccountCompliance { $failureReasons = $nonCompliantUsers | ForEach-Object { $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } - "$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')" + "$($_.UserName)|$($_.Roles)|$accountType|$($missingLicenses -join ',')" } $failureReasons = $failureReasons -join "`n" + $details = if ($nonCompliantUsers) { - "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" - } - else { + "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" + } else { "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" } + $failureReason = if ($nonCompliantUsers) { + "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" + } else { + "N/A" + } + $result = $nonCompliantUsers.Count -eq 0 $status = if ($result) { 'Pass' } else { 'Fail' } - $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" } - # Create the parameter splat $params = @{ Rec = $recnum Result = $result @@ -79,13 +99,11 @@ function Test-AdministrativeAccountCompliance { catch { Write-Error "An error occurred during the test: $_" - # Retrieve the description from the test definitions $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) - # Call Initialize-CISAuditResult with error parameters $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure } } From d58d0b664d61f96440c080dc4aab8c99288953ad Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:25:47 -0500 Subject: [PATCH 25/45] docs: Update CHANGELOG --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f722e7..052ba39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ The format is based on and uses the types of changes according to [Keep a Change - Updated `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` functions to use `Format-MissingActions` for structuring missing actions into a pipe-separated table format. - Added more verbose logging to `Test-BlockMailForwarding` and improved error handling for better troubleshooting. - 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. ### Fixed @@ -22,6 +24,13 @@ The format is based on and uses the types of changes according to [Keep a Change - Corrected the usage of the join operation within `$details` in `Test-BlockMailForwarding` to handle arrays properly. - Fixed the logic in `Test-RestrictCustomScripts` to accurately replace and manage URLs, ensuring compliance checks are correctly performed. - Updated the `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` functions to handle the `$allFailures` variable correctly, ensuring accurate pass/fail results. +- Fixed the connections in helper CSV and connect function. +- Removed verbose preference from `Test-RestrictCustomScripts`. +- Ensured that the output in `Test-BlockMailForwarding` does not include extra spaces between table headers and data. +- Fixed output in `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` to correctly align with the new table format. +- Added step 1 and step 2 in `Test-BlockMailForwarding` details to ensure comprehensive compliance checks. +- 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 From f6aa4b83dde98e2725b01ea0ce07de8027127f8e Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:27:34 -0500 Subject: [PATCH 26/45] add: parameter validation for excel and csv path in sync function --- source/Public/Sync-CISExcelAndCsvData.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/Public/Sync-CISExcelAndCsvData.ps1 b/source/Public/Sync-CISExcelAndCsvData.ps1 index 378aba4..22d84b4 100644 --- a/source/Public/Sync-CISExcelAndCsvData.ps1 +++ b/source/Public/Sync-CISExcelAndCsvData.ps1 @@ -34,12 +34,14 @@ function Sync-CISExcelAndCsvData { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] + [ValidateScript({ Test-Path $_ })] [string]$ExcelPath, [Parameter(Mandatory = $true)] [string]$WorksheetName, [Parameter(Mandatory = $true)] + [ValidateScript({ Test-Path $_ })] [string]$CsvPath, [Parameter(Mandatory = $false)] From 70dcd746431ae9097a020a31b5b043aa50ddfff7 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:28:13 -0500 Subject: [PATCH 27/45] docs: Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 052ba39..a5f4a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ 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 ### Fixed From 41dbf2f0dbaf191337c5fd92d64defee3cc5828f Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:31:40 -0500 Subject: [PATCH 28/45] add: Output type to tests. --- source/tests/Test-AdministrativeAccountCompliance.ps1 | 1 + source/tests/Test-AntiPhishingPolicy.ps1 | 1 + source/tests/Test-AuditDisabledFalse.ps1 | 1 + source/tests/Test-AuditLogSearch.ps1 | 1 + source/tests/Test-BlockChannelEmails.ps1 | 1 + source/tests/Test-BlockMailForwarding.ps1 | 1 + source/tests/Test-BlockSharedMailboxSignIn.ps1 | 1 + source/tests/Test-CommonAttachmentFilter.ps1 | 1 + source/tests/Test-CustomerLockbox.ps1 | 1 + source/tests/Test-DialInBypassLobby.ps1 | 1 + source/tests/Test-DisallowInfectedFilesDownload.ps1 | 1 + source/tests/Test-EnableDKIM.ps1 | 1 + source/tests/Test-ExternalNoControl.ps1 | 1 + source/tests/Test-ExternalSharingCalendars.ps1 | 1 + source/tests/Test-GlobalAdminsCount.ps1 | 1 + source/tests/Test-GuestAccessExpiration.ps1 | 1 + source/tests/Test-GuestUsersBiweeklyReview.ps1 | 1 + source/tests/Test-IdentifyExternalEmail.ps1 | 1 + source/tests/Test-LinkSharingRestrictions.ps1 | 1 + source/tests/Test-MailTipsEnabled.ps1 | 1 + source/tests/Test-MailboxAuditingE3.ps1 | 1 + source/tests/Test-MailboxAuditingE5.ps1 | 1 + source/tests/Test-ManagedApprovedPublicGroups.ps1 | 1 + source/tests/Test-MeetingChatNoAnonymous.ps1 | 1 + source/tests/Test-ModernAuthExchangeOnline.ps1 | 1 + source/tests/Test-ModernAuthSharePoint.ps1 | 1 + source/tests/Test-NoAnonymousMeetingJoin.ps1 | 1 + source/tests/Test-NoAnonymousMeetingStart.ps1 | 1 + source/tests/Test-NoWhitelistDomains.ps1 | 1 + source/tests/Test-NotifyMalwareInternal.ps1 | 1 + source/tests/Test-OneDriveContentRestrictions.ps1 | 1 + source/tests/Test-OneDriveSyncRestrictions.ps1 | 1 + source/tests/Test-OrgOnlyBypassLobby.ps1 | 1 + source/tests/Test-OrganizersPresent.ps1 | 1 + source/tests/Test-PasswordHashSync.ps1 | 1 + source/tests/Test-PasswordNeverExpirePolicy.ps1 | 1 + source/tests/Test-ReauthWithCode.ps1 | 1 + source/tests/Test-ReportSecurityInTeams.ps1 | 1 + source/tests/Test-RestrictCustomScripts.ps1 | 1 + source/tests/Test-RestrictExternalSharing.ps1 | 1 + source/tests/Test-RestrictOutlookAddins.ps1 | 1 + source/tests/Test-RestrictStorageProvidersOutlook.ps1 | 1 + source/tests/Test-RestrictTenantCreation.ps1 | 1 + source/tests/Test-SafeAttachmentsPolicy.ps1 | 1 + source/tests/Test-SafeAttachmentsTeams.ps1 | 1 + source/tests/Test-SafeLinksOfficeApps.ps1 | 1 + source/tests/Test-SharePointAADB2B.ps1 | 1 + source/tests/Test-SharePointExternalSharingDomains.ps1 | 1 + source/tests/Test-SharePointGuestsItemSharing.ps1 | 1 + source/tests/Test-SpamPolicyAdminNotify.ps1 | 1 + source/tests/Test-TeamsExternalAccess.ps1 | 1 + source/tests/Test-TeamsExternalFileSharing.ps1 | 1 + 52 files changed, 52 insertions(+) diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 1b22bdb..b905033 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -1,6 +1,7 @@ function Test-AdministrativeAccountCompliance { [CmdletBinding()] [OutputType([CISAuditResult])] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-AntiPhishingPolicy.ps1 b/source/tests/Test-AntiPhishingPolicy.ps1 index c36b20c..4e4de8c 100644 --- a/source/tests/Test-AntiPhishingPolicy.ps1 +++ b/source/tests/Test-AntiPhishingPolicy.ps1 @@ -1,5 +1,6 @@ function Test-AntiPhishingPolicy { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-AuditDisabledFalse.ps1 b/source/tests/Test-AuditDisabledFalse.ps1 index e8c4688..8a26323 100644 --- a/source/tests/Test-AuditDisabledFalse.ps1 +++ b/source/tests/Test-AuditDisabledFalse.ps1 @@ -1,5 +1,6 @@ function Test-AuditDisabledFalse { [CmdletBinding()] + [OutputType([CISAuditResult])] # Aligned param ( # Parameters can be added if needed diff --git a/source/tests/Test-AuditLogSearch.ps1 b/source/tests/Test-AuditLogSearch.ps1 index 2ffec8a..bbedbca 100644 --- a/source/tests/Test-AuditLogSearch.ps1 +++ b/source/tests/Test-AuditLogSearch.ps1 @@ -1,5 +1,6 @@ function Test-AuditLogSearch { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-BlockChannelEmails.ps1 b/source/tests/Test-BlockChannelEmails.ps1 index 623a882..5165b61 100644 --- a/source/tests/Test-BlockChannelEmails.ps1 +++ b/source/tests/Test-BlockChannelEmails.ps1 @@ -1,5 +1,6 @@ function Test-BlockChannelEmails { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index 692dda2..0ea1c1b 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -1,5 +1,6 @@ function Test-BlockMailForwarding { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-BlockSharedMailboxSignIn.ps1 b/source/tests/Test-BlockSharedMailboxSignIn.ps1 index 5561a3d..d1af582 100644 --- a/source/tests/Test-BlockSharedMailboxSignIn.ps1 +++ b/source/tests/Test-BlockSharedMailboxSignIn.ps1 @@ -1,5 +1,6 @@ function Test-BlockSharedMailboxSignIn { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-CommonAttachmentFilter.ps1 b/source/tests/Test-CommonAttachmentFilter.ps1 index 662529a..3341ca5 100644 --- a/source/tests/Test-CommonAttachmentFilter.ps1 +++ b/source/tests/Test-CommonAttachmentFilter.ps1 @@ -1,5 +1,6 @@ function Test-CommonAttachmentFilter { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-CustomerLockbox.ps1 b/source/tests/Test-CustomerLockbox.ps1 index b22773b..8396ffc 100644 --- a/source/tests/Test-CustomerLockbox.ps1 +++ b/source/tests/Test-CustomerLockbox.ps1 @@ -1,5 +1,6 @@ function Test-CustomerLockbox { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-DialInBypassLobby.ps1 b/source/tests/Test-DialInBypassLobby.ps1 index d9449b4..b7088ee 100644 --- a/source/tests/Test-DialInBypassLobby.ps1 +++ b/source/tests/Test-DialInBypassLobby.ps1 @@ -1,5 +1,6 @@ function Test-DialInBypassLobby { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-DisallowInfectedFilesDownload.ps1 b/source/tests/Test-DisallowInfectedFilesDownload.ps1 index 538e998..514dda7 100644 --- a/source/tests/Test-DisallowInfectedFilesDownload.ps1 +++ b/source/tests/Test-DisallowInfectedFilesDownload.ps1 @@ -1,5 +1,6 @@ function Test-DisallowInfectedFilesDownload { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-EnableDKIM.ps1 b/source/tests/Test-EnableDKIM.ps1 index db793c5..a6662e1 100644 --- a/source/tests/Test-EnableDKIM.ps1 +++ b/source/tests/Test-EnableDKIM.ps1 @@ -1,5 +1,6 @@ function Test-EnableDKIM { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-ExternalNoControl.ps1 b/source/tests/Test-ExternalNoControl.ps1 index 0fce827..1a8c82d 100644 --- a/source/tests/Test-ExternalNoControl.ps1 +++ b/source/tests/Test-ExternalNoControl.ps1 @@ -1,5 +1,6 @@ function Test-ExternalNoControl { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-ExternalSharingCalendars.ps1 b/source/tests/Test-ExternalSharingCalendars.ps1 index 3f0c7a6..ed5e941 100644 --- a/source/tests/Test-ExternalSharingCalendars.ps1 +++ b/source/tests/Test-ExternalSharingCalendars.ps1 @@ -1,5 +1,6 @@ function Test-ExternalSharingCalendars { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index 1a7525e..e0188f4 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -1,5 +1,6 @@ function Test-GlobalAdminsCount { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-GuestAccessExpiration.ps1 b/source/tests/Test-GuestAccessExpiration.ps1 index cef642f..986c8d7 100644 --- a/source/tests/Test-GuestAccessExpiration.ps1 +++ b/source/tests/Test-GuestAccessExpiration.ps1 @@ -1,5 +1,6 @@ function Test-GuestAccessExpiration { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-GuestUsersBiweeklyReview.ps1 b/source/tests/Test-GuestUsersBiweeklyReview.ps1 index 0aeb409..757c4d3 100644 --- a/source/tests/Test-GuestUsersBiweeklyReview.ps1 +++ b/source/tests/Test-GuestUsersBiweeklyReview.ps1 @@ -1,5 +1,6 @@ function Test-GuestUsersBiweeklyReview { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-IdentifyExternalEmail.ps1 b/source/tests/Test-IdentifyExternalEmail.ps1 index 6c43794..63bce34 100644 --- a/source/tests/Test-IdentifyExternalEmail.ps1 +++ b/source/tests/Test-IdentifyExternalEmail.ps1 @@ -1,5 +1,6 @@ function Test-IdentifyExternalEmail { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-LinkSharingRestrictions.ps1 b/source/tests/Test-LinkSharingRestrictions.ps1 index cc96c15..24cd22b 100644 --- a/source/tests/Test-LinkSharingRestrictions.ps1 +++ b/source/tests/Test-LinkSharingRestrictions.ps1 @@ -1,5 +1,6 @@ function Test-LinkSharingRestrictions { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-MailTipsEnabled.ps1 b/source/tests/Test-MailTipsEnabled.ps1 index c093dea..2ccf106 100644 --- a/source/tests/Test-MailTipsEnabled.ps1 +++ b/source/tests/Test-MailTipsEnabled.ps1 @@ -1,5 +1,6 @@ function Test-MailTipsEnabled { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index ad6364b..26e6379 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -1,5 +1,6 @@ function Test-MailboxAuditingE3 { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index 539b628..af40be6 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -1,5 +1,6 @@ function Test-MailboxAuditingE5 { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-ManagedApprovedPublicGroups.ps1 b/source/tests/Test-ManagedApprovedPublicGroups.ps1 index 94512ff..073d540 100644 --- a/source/tests/Test-ManagedApprovedPublicGroups.ps1 +++ b/source/tests/Test-ManagedApprovedPublicGroups.ps1 @@ -1,5 +1,6 @@ function Test-ManagedApprovedPublicGroups { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-MeetingChatNoAnonymous.ps1 b/source/tests/Test-MeetingChatNoAnonymous.ps1 index 12764be..3524c6b 100644 --- a/source/tests/Test-MeetingChatNoAnonymous.ps1 +++ b/source/tests/Test-MeetingChatNoAnonymous.ps1 @@ -1,5 +1,6 @@ function Test-MeetingChatNoAnonymous { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-ModernAuthExchangeOnline.ps1 b/source/tests/Test-ModernAuthExchangeOnline.ps1 index 2c5c79e..8735fa4 100644 --- a/source/tests/Test-ModernAuthExchangeOnline.ps1 +++ b/source/tests/Test-ModernAuthExchangeOnline.ps1 @@ -1,5 +1,6 @@ function Test-ModernAuthExchangeOnline { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-ModernAuthSharePoint.ps1 b/source/tests/Test-ModernAuthSharePoint.ps1 index 990a64d..c56ef59 100644 --- a/source/tests/Test-ModernAuthSharePoint.ps1 +++ b/source/tests/Test-ModernAuthSharePoint.ps1 @@ -1,5 +1,6 @@ function Test-ModernAuthSharePoint { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-NoAnonymousMeetingJoin.ps1 b/source/tests/Test-NoAnonymousMeetingJoin.ps1 index 6a9336a..e28ebdb 100644 --- a/source/tests/Test-NoAnonymousMeetingJoin.ps1 +++ b/source/tests/Test-NoAnonymousMeetingJoin.ps1 @@ -1,5 +1,6 @@ function Test-NoAnonymousMeetingJoin { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-NoAnonymousMeetingStart.ps1 b/source/tests/Test-NoAnonymousMeetingStart.ps1 index 9820b84..5ffa6e2 100644 --- a/source/tests/Test-NoAnonymousMeetingStart.ps1 +++ b/source/tests/Test-NoAnonymousMeetingStart.ps1 @@ -1,5 +1,6 @@ function Test-NoAnonymousMeetingStart { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-NoWhitelistDomains.ps1 b/source/tests/Test-NoWhitelistDomains.ps1 index fe9ea6b..d51fdc1 100644 --- a/source/tests/Test-NoWhitelistDomains.ps1 +++ b/source/tests/Test-NoWhitelistDomains.ps1 @@ -1,5 +1,6 @@ function Test-NoWhitelistDomains { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-NotifyMalwareInternal.ps1 b/source/tests/Test-NotifyMalwareInternal.ps1 index eba1e84..1e466fb 100644 --- a/source/tests/Test-NotifyMalwareInternal.ps1 +++ b/source/tests/Test-NotifyMalwareInternal.ps1 @@ -1,5 +1,6 @@ function Test-NotifyMalwareInternal { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-OneDriveContentRestrictions.ps1 b/source/tests/Test-OneDriveContentRestrictions.ps1 index 5d10b50..0043aa9 100644 --- a/source/tests/Test-OneDriveContentRestrictions.ps1 +++ b/source/tests/Test-OneDriveContentRestrictions.ps1 @@ -1,5 +1,6 @@ function Test-OneDriveContentRestrictions { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-OneDriveSyncRestrictions.ps1 b/source/tests/Test-OneDriveSyncRestrictions.ps1 index b0af3df..436899a 100644 --- a/source/tests/Test-OneDriveSyncRestrictions.ps1 +++ b/source/tests/Test-OneDriveSyncRestrictions.ps1 @@ -1,5 +1,6 @@ function Test-OneDriveSyncRestrictions { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-OrgOnlyBypassLobby.ps1 b/source/tests/Test-OrgOnlyBypassLobby.ps1 index 9ad8958..735c86d 100644 --- a/source/tests/Test-OrgOnlyBypassLobby.ps1 +++ b/source/tests/Test-OrgOnlyBypassLobby.ps1 @@ -1,5 +1,6 @@ function Test-OrgOnlyBypassLobby { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-OrganizersPresent.ps1 b/source/tests/Test-OrganizersPresent.ps1 index 8e2fead..014d13d 100644 --- a/source/tests/Test-OrganizersPresent.ps1 +++ b/source/tests/Test-OrganizersPresent.ps1 @@ -1,5 +1,6 @@ function Test-OrganizersPresent { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-PasswordHashSync.ps1 b/source/tests/Test-PasswordHashSync.ps1 index dfde80f..83e6d9d 100644 --- a/source/tests/Test-PasswordHashSync.ps1 +++ b/source/tests/Test-PasswordHashSync.ps1 @@ -1,5 +1,6 @@ function Test-PasswordHashSync { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index 144a8d7..a4f9a07 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -1,5 +1,6 @@ function Test-PasswordNeverExpirePolicy { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned [Parameter(Mandatory)] diff --git a/source/tests/Test-ReauthWithCode.ps1 b/source/tests/Test-ReauthWithCode.ps1 index 318bade..6adfd31 100644 --- a/source/tests/Test-ReauthWithCode.ps1 +++ b/source/tests/Test-ReauthWithCode.ps1 @@ -1,5 +1,6 @@ function Test-ReauthWithCode { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-ReportSecurityInTeams.ps1 b/source/tests/Test-ReportSecurityInTeams.ps1 index aceaf1b..9c889dd 100644 --- a/source/tests/Test-ReportSecurityInTeams.ps1 +++ b/source/tests/Test-ReportSecurityInTeams.ps1 @@ -1,5 +1,6 @@ function Test-ReportSecurityInTeams { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 99daa5a..fea4a0f 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -1,5 +1,6 @@ function Test-RestrictCustomScripts { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Define your parameters here if needed ) diff --git a/source/tests/Test-RestrictExternalSharing.ps1 b/source/tests/Test-RestrictExternalSharing.ps1 index 0276204..04b00eb 100644 --- a/source/tests/Test-RestrictExternalSharing.ps1 +++ b/source/tests/Test-RestrictExternalSharing.ps1 @@ -1,5 +1,6 @@ function Test-RestrictExternalSharing { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-RestrictOutlookAddins.ps1 b/source/tests/Test-RestrictOutlookAddins.ps1 index 6d28405..39f1ae6 100644 --- a/source/tests/Test-RestrictOutlookAddins.ps1 +++ b/source/tests/Test-RestrictOutlookAddins.ps1 @@ -1,5 +1,6 @@ function Test-RestrictOutlookAddins { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters could include credentials or other necessary data diff --git a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 index d6d5235..fa7b256 100644 --- a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 +++ b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 @@ -1,5 +1,6 @@ function Test-RestrictStorageProvidersOutlook { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed diff --git a/source/tests/Test-RestrictTenantCreation.ps1 b/source/tests/Test-RestrictTenantCreation.ps1 index be6a148..ede53c4 100644 --- a/source/tests/Test-RestrictTenantCreation.ps1 +++ b/source/tests/Test-RestrictTenantCreation.ps1 @@ -1,5 +1,6 @@ function Test-RestrictTenantCreation { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeAttachmentsPolicy.ps1 b/source/tests/Test-SafeAttachmentsPolicy.ps1 index 3e5ad4f..18a90a2 100644 --- a/source/tests/Test-SafeAttachmentsPolicy.ps1 +++ b/source/tests/Test-SafeAttachmentsPolicy.ps1 @@ -1,5 +1,6 @@ function Test-SafeAttachmentsPolicy { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeAttachmentsTeams.ps1 b/source/tests/Test-SafeAttachmentsTeams.ps1 index f87a437..1fae789 100644 --- a/source/tests/Test-SafeAttachmentsTeams.ps1 +++ b/source/tests/Test-SafeAttachmentsTeams.ps1 @@ -1,5 +1,6 @@ function Test-SafeAttachmentsTeams { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeLinksOfficeApps.ps1 b/source/tests/Test-SafeLinksOfficeApps.ps1 index 0e1cfed..aa30dbc 100644 --- a/source/tests/Test-SafeLinksOfficeApps.ps1 +++ b/source/tests/Test-SafeLinksOfficeApps.ps1 @@ -1,5 +1,6 @@ function Test-SafeLinksOfficeApps { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-SharePointAADB2B.ps1 b/source/tests/Test-SharePointAADB2B.ps1 index 7dfde4d..c95e415 100644 --- a/source/tests/Test-SharePointAADB2B.ps1 +++ b/source/tests/Test-SharePointAADB2B.ps1 @@ -1,5 +1,6 @@ function Test-SharePointAADB2B { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SharePointExternalSharingDomains.ps1 b/source/tests/Test-SharePointExternalSharingDomains.ps1 index 848cba4..ee309d7 100644 --- a/source/tests/Test-SharePointExternalSharingDomains.ps1 +++ b/source/tests/Test-SharePointExternalSharingDomains.ps1 @@ -1,5 +1,6 @@ function Test-SharePointExternalSharingDomains { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SharePointGuestsItemSharing.ps1 b/source/tests/Test-SharePointGuestsItemSharing.ps1 index aade0b3..75159b4 100644 --- a/source/tests/Test-SharePointGuestsItemSharing.ps1 +++ b/source/tests/Test-SharePointGuestsItemSharing.ps1 @@ -1,5 +1,6 @@ function Test-SharePointGuestsItemSharing { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SpamPolicyAdminNotify.ps1 b/source/tests/Test-SpamPolicyAdminNotify.ps1 index 8bb73bc..8f100c7 100644 --- a/source/tests/Test-SpamPolicyAdminNotify.ps1 +++ b/source/tests/Test-SpamPolicyAdminNotify.ps1 @@ -1,5 +1,6 @@ function Test-SpamPolicyAdminNotify { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-TeamsExternalAccess.ps1 b/source/tests/Test-TeamsExternalAccess.ps1 index 059cdf7..aec7caa 100644 --- a/source/tests/Test-TeamsExternalAccess.ps1 +++ b/source/tests/Test-TeamsExternalAccess.ps1 @@ -1,5 +1,6 @@ function Test-TeamsExternalAccess { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-TeamsExternalFileSharing.ps1 b/source/tests/Test-TeamsExternalFileSharing.ps1 index 4004dcc..92ef78c 100644 --- a/source/tests/Test-TeamsExternalFileSharing.ps1 +++ b/source/tests/Test-TeamsExternalFileSharing.ps1 @@ -1,5 +1,6 @@ function Test-TeamsExternalFileSharing { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed From 2d9a1a1d102850288c49905a8e985a70502aaf56 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:32:10 -0500 Subject: [PATCH 29/45] docs: Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5f4a0a..59cf0c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on and uses the types of changes according to [Keep a Change - Added sorting to output. - Created new functions for improved modularity. - Parameter validation for excel and csv path in sync function +- Added Output type to tests. ### Fixed From bb1df1112854f64992a8aa959ae8a210b34fb3e3 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:34:21 -0500 Subject: [PATCH 30/45] add: Output type to tests. --- source/tests/Test-AdministrativeAccountCompliance.ps1 | 1 - source/tests/Test-AntiPhishingPolicy.ps1 | 1 - source/tests/Test-AuditDisabledFalse.ps1 | 1 - source/tests/Test-AuditLogSearch.ps1 | 1 - source/tests/Test-BlockChannelEmails.ps1 | 1 - source/tests/Test-BlockMailForwarding.ps1 | 1 - source/tests/Test-BlockSharedMailboxSignIn.ps1 | 1 - source/tests/Test-CommonAttachmentFilter.ps1 | 1 - source/tests/Test-CustomerLockbox.ps1 | 1 - source/tests/Test-DialInBypassLobby.ps1 | 1 - source/tests/Test-DisallowInfectedFilesDownload.ps1 | 1 - source/tests/Test-EnableDKIM.ps1 | 1 - source/tests/Test-ExternalNoControl.ps1 | 1 - source/tests/Test-ExternalSharingCalendars.ps1 | 1 - source/tests/Test-GlobalAdminsCount.ps1 | 1 - source/tests/Test-GuestAccessExpiration.ps1 | 1 - source/tests/Test-GuestUsersBiweeklyReview.ps1 | 1 - source/tests/Test-IdentifyExternalEmail.ps1 | 1 - source/tests/Test-LinkSharingRestrictions.ps1 | 1 - source/tests/Test-MailTipsEnabled.ps1 | 1 - source/tests/Test-MailboxAuditingE3.ps1 | 1 - source/tests/Test-MailboxAuditingE5.ps1 | 1 - source/tests/Test-ManagedApprovedPublicGroups.ps1 | 1 - source/tests/Test-MeetingChatNoAnonymous.ps1 | 1 - source/tests/Test-ModernAuthExchangeOnline.ps1 | 1 - source/tests/Test-ModernAuthSharePoint.ps1 | 1 - source/tests/Test-NoAnonymousMeetingJoin.ps1 | 1 - source/tests/Test-NoAnonymousMeetingStart.ps1 | 1 - source/tests/Test-NoWhitelistDomains.ps1 | 1 - source/tests/Test-NotifyMalwareInternal.ps1 | 1 - source/tests/Test-OneDriveContentRestrictions.ps1 | 1 - source/tests/Test-OneDriveSyncRestrictions.ps1 | 1 - source/tests/Test-OrgOnlyBypassLobby.ps1 | 1 - source/tests/Test-OrganizersPresent.ps1 | 1 - source/tests/Test-PasswordHashSync.ps1 | 1 - source/tests/Test-PasswordNeverExpirePolicy.ps1 | 1 - source/tests/Test-ReauthWithCode.ps1 | 1 - source/tests/Test-ReportSecurityInTeams.ps1 | 1 - source/tests/Test-RestrictCustomScripts.ps1 | 1 - source/tests/Test-RestrictExternalSharing.ps1 | 1 - source/tests/Test-RestrictOutlookAddins.ps1 | 1 - source/tests/Test-RestrictStorageProvidersOutlook.ps1 | 1 - source/tests/Test-RestrictTenantCreation.ps1 | 1 - source/tests/Test-SafeAttachmentsPolicy.ps1 | 1 - source/tests/Test-SafeAttachmentsTeams.ps1 | 1 - source/tests/Test-SafeLinksOfficeApps.ps1 | 1 - source/tests/Test-SharePointAADB2B.ps1 | 1 - source/tests/Test-SharePointExternalSharingDomains.ps1 | 1 - source/tests/Test-SharePointGuestsItemSharing.ps1 | 1 - source/tests/Test-SpamPolicyAdminNotify.ps1 | 1 - source/tests/Test-TeamsExternalAccess.ps1 | 1 - source/tests/Test-TeamsExternalFileSharing.ps1 | 1 - 52 files changed, 52 deletions(-) diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index b905033..1b22bdb 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -1,7 +1,6 @@ function Test-AdministrativeAccountCompliance { [CmdletBinding()] [OutputType([CISAuditResult])] - [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-AntiPhishingPolicy.ps1 b/source/tests/Test-AntiPhishingPolicy.ps1 index 4e4de8c..c36b20c 100644 --- a/source/tests/Test-AntiPhishingPolicy.ps1 +++ b/source/tests/Test-AntiPhishingPolicy.ps1 @@ -1,6 +1,5 @@ function Test-AntiPhishingPolicy { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-AuditDisabledFalse.ps1 b/source/tests/Test-AuditDisabledFalse.ps1 index 8a26323..e8c4688 100644 --- a/source/tests/Test-AuditDisabledFalse.ps1 +++ b/source/tests/Test-AuditDisabledFalse.ps1 @@ -1,6 +1,5 @@ function Test-AuditDisabledFalse { [CmdletBinding()] - [OutputType([CISAuditResult])] # Aligned param ( # Parameters can be added if needed diff --git a/source/tests/Test-AuditLogSearch.ps1 b/source/tests/Test-AuditLogSearch.ps1 index bbedbca..2ffec8a 100644 --- a/source/tests/Test-AuditLogSearch.ps1 +++ b/source/tests/Test-AuditLogSearch.ps1 @@ -1,6 +1,5 @@ function Test-AuditLogSearch { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-BlockChannelEmails.ps1 b/source/tests/Test-BlockChannelEmails.ps1 index 5165b61..623a882 100644 --- a/source/tests/Test-BlockChannelEmails.ps1 +++ b/source/tests/Test-BlockChannelEmails.ps1 @@ -1,6 +1,5 @@ function Test-BlockChannelEmails { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index 0ea1c1b..692dda2 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -1,6 +1,5 @@ function Test-BlockMailForwarding { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-BlockSharedMailboxSignIn.ps1 b/source/tests/Test-BlockSharedMailboxSignIn.ps1 index d1af582..5561a3d 100644 --- a/source/tests/Test-BlockSharedMailboxSignIn.ps1 +++ b/source/tests/Test-BlockSharedMailboxSignIn.ps1 @@ -1,6 +1,5 @@ function Test-BlockSharedMailboxSignIn { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-CommonAttachmentFilter.ps1 b/source/tests/Test-CommonAttachmentFilter.ps1 index 3341ca5..662529a 100644 --- a/source/tests/Test-CommonAttachmentFilter.ps1 +++ b/source/tests/Test-CommonAttachmentFilter.ps1 @@ -1,6 +1,5 @@ function Test-CommonAttachmentFilter { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-CustomerLockbox.ps1 b/source/tests/Test-CustomerLockbox.ps1 index 8396ffc..b22773b 100644 --- a/source/tests/Test-CustomerLockbox.ps1 +++ b/source/tests/Test-CustomerLockbox.ps1 @@ -1,6 +1,5 @@ function Test-CustomerLockbox { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-DialInBypassLobby.ps1 b/source/tests/Test-DialInBypassLobby.ps1 index b7088ee..d9449b4 100644 --- a/source/tests/Test-DialInBypassLobby.ps1 +++ b/source/tests/Test-DialInBypassLobby.ps1 @@ -1,6 +1,5 @@ function Test-DialInBypassLobby { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-DisallowInfectedFilesDownload.ps1 b/source/tests/Test-DisallowInfectedFilesDownload.ps1 index 514dda7..538e998 100644 --- a/source/tests/Test-DisallowInfectedFilesDownload.ps1 +++ b/source/tests/Test-DisallowInfectedFilesDownload.ps1 @@ -1,6 +1,5 @@ function Test-DisallowInfectedFilesDownload { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-EnableDKIM.ps1 b/source/tests/Test-EnableDKIM.ps1 index a6662e1..db793c5 100644 --- a/source/tests/Test-EnableDKIM.ps1 +++ b/source/tests/Test-EnableDKIM.ps1 @@ -1,6 +1,5 @@ function Test-EnableDKIM { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-ExternalNoControl.ps1 b/source/tests/Test-ExternalNoControl.ps1 index 1a8c82d..0fce827 100644 --- a/source/tests/Test-ExternalNoControl.ps1 +++ b/source/tests/Test-ExternalNoControl.ps1 @@ -1,6 +1,5 @@ function Test-ExternalNoControl { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-ExternalSharingCalendars.ps1 b/source/tests/Test-ExternalSharingCalendars.ps1 index ed5e941..3f0c7a6 100644 --- a/source/tests/Test-ExternalSharingCalendars.ps1 +++ b/source/tests/Test-ExternalSharingCalendars.ps1 @@ -1,6 +1,5 @@ function Test-ExternalSharingCalendars { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index e0188f4..1a7525e 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -1,6 +1,5 @@ function Test-GlobalAdminsCount { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-GuestAccessExpiration.ps1 b/source/tests/Test-GuestAccessExpiration.ps1 index 986c8d7..cef642f 100644 --- a/source/tests/Test-GuestAccessExpiration.ps1 +++ b/source/tests/Test-GuestAccessExpiration.ps1 @@ -1,6 +1,5 @@ function Test-GuestAccessExpiration { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-GuestUsersBiweeklyReview.ps1 b/source/tests/Test-GuestUsersBiweeklyReview.ps1 index 757c4d3..0aeb409 100644 --- a/source/tests/Test-GuestUsersBiweeklyReview.ps1 +++ b/source/tests/Test-GuestUsersBiweeklyReview.ps1 @@ -1,6 +1,5 @@ function Test-GuestUsersBiweeklyReview { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-IdentifyExternalEmail.ps1 b/source/tests/Test-IdentifyExternalEmail.ps1 index 63bce34..6c43794 100644 --- a/source/tests/Test-IdentifyExternalEmail.ps1 +++ b/source/tests/Test-IdentifyExternalEmail.ps1 @@ -1,6 +1,5 @@ function Test-IdentifyExternalEmail { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-LinkSharingRestrictions.ps1 b/source/tests/Test-LinkSharingRestrictions.ps1 index 24cd22b..cc96c15 100644 --- a/source/tests/Test-LinkSharingRestrictions.ps1 +++ b/source/tests/Test-LinkSharingRestrictions.ps1 @@ -1,6 +1,5 @@ function Test-LinkSharingRestrictions { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-MailTipsEnabled.ps1 b/source/tests/Test-MailTipsEnabled.ps1 index 2ccf106..c093dea 100644 --- a/source/tests/Test-MailTipsEnabled.ps1 +++ b/source/tests/Test-MailTipsEnabled.ps1 @@ -1,6 +1,5 @@ function Test-MailTipsEnabled { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index 26e6379..ad6364b 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -1,6 +1,5 @@ function Test-MailboxAuditingE3 { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index af40be6..539b628 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -1,6 +1,5 @@ function Test-MailboxAuditingE5 { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-ManagedApprovedPublicGroups.ps1 b/source/tests/Test-ManagedApprovedPublicGroups.ps1 index 073d540..94512ff 100644 --- a/source/tests/Test-ManagedApprovedPublicGroups.ps1 +++ b/source/tests/Test-ManagedApprovedPublicGroups.ps1 @@ -1,6 +1,5 @@ function Test-ManagedApprovedPublicGroups { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-MeetingChatNoAnonymous.ps1 b/source/tests/Test-MeetingChatNoAnonymous.ps1 index 3524c6b..12764be 100644 --- a/source/tests/Test-MeetingChatNoAnonymous.ps1 +++ b/source/tests/Test-MeetingChatNoAnonymous.ps1 @@ -1,6 +1,5 @@ function Test-MeetingChatNoAnonymous { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-ModernAuthExchangeOnline.ps1 b/source/tests/Test-ModernAuthExchangeOnline.ps1 index 8735fa4..2c5c79e 100644 --- a/source/tests/Test-ModernAuthExchangeOnline.ps1 +++ b/source/tests/Test-ModernAuthExchangeOnline.ps1 @@ -1,6 +1,5 @@ function Test-ModernAuthExchangeOnline { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-ModernAuthSharePoint.ps1 b/source/tests/Test-ModernAuthSharePoint.ps1 index c56ef59..990a64d 100644 --- a/source/tests/Test-ModernAuthSharePoint.ps1 +++ b/source/tests/Test-ModernAuthSharePoint.ps1 @@ -1,6 +1,5 @@ function Test-ModernAuthSharePoint { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-NoAnonymousMeetingJoin.ps1 b/source/tests/Test-NoAnonymousMeetingJoin.ps1 index e28ebdb..6a9336a 100644 --- a/source/tests/Test-NoAnonymousMeetingJoin.ps1 +++ b/source/tests/Test-NoAnonymousMeetingJoin.ps1 @@ -1,6 +1,5 @@ function Test-NoAnonymousMeetingJoin { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-NoAnonymousMeetingStart.ps1 b/source/tests/Test-NoAnonymousMeetingStart.ps1 index 5ffa6e2..9820b84 100644 --- a/source/tests/Test-NoAnonymousMeetingStart.ps1 +++ b/source/tests/Test-NoAnonymousMeetingStart.ps1 @@ -1,6 +1,5 @@ function Test-NoAnonymousMeetingStart { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-NoWhitelistDomains.ps1 b/source/tests/Test-NoWhitelistDomains.ps1 index d51fdc1..fe9ea6b 100644 --- a/source/tests/Test-NoWhitelistDomains.ps1 +++ b/source/tests/Test-NoWhitelistDomains.ps1 @@ -1,6 +1,5 @@ function Test-NoWhitelistDomains { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-NotifyMalwareInternal.ps1 b/source/tests/Test-NotifyMalwareInternal.ps1 index 1e466fb..eba1e84 100644 --- a/source/tests/Test-NotifyMalwareInternal.ps1 +++ b/source/tests/Test-NotifyMalwareInternal.ps1 @@ -1,6 +1,5 @@ function Test-NotifyMalwareInternal { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-OneDriveContentRestrictions.ps1 b/source/tests/Test-OneDriveContentRestrictions.ps1 index 0043aa9..5d10b50 100644 --- a/source/tests/Test-OneDriveContentRestrictions.ps1 +++ b/source/tests/Test-OneDriveContentRestrictions.ps1 @@ -1,6 +1,5 @@ function Test-OneDriveContentRestrictions { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-OneDriveSyncRestrictions.ps1 b/source/tests/Test-OneDriveSyncRestrictions.ps1 index 436899a..b0af3df 100644 --- a/source/tests/Test-OneDriveSyncRestrictions.ps1 +++ b/source/tests/Test-OneDriveSyncRestrictions.ps1 @@ -1,6 +1,5 @@ function Test-OneDriveSyncRestrictions { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-OrgOnlyBypassLobby.ps1 b/source/tests/Test-OrgOnlyBypassLobby.ps1 index 735c86d..9ad8958 100644 --- a/source/tests/Test-OrgOnlyBypassLobby.ps1 +++ b/source/tests/Test-OrgOnlyBypassLobby.ps1 @@ -1,6 +1,5 @@ function Test-OrgOnlyBypassLobby { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-OrganizersPresent.ps1 b/source/tests/Test-OrganizersPresent.ps1 index 014d13d..8e2fead 100644 --- a/source/tests/Test-OrganizersPresent.ps1 +++ b/source/tests/Test-OrganizersPresent.ps1 @@ -1,6 +1,5 @@ function Test-OrganizersPresent { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-PasswordHashSync.ps1 b/source/tests/Test-PasswordHashSync.ps1 index 83e6d9d..dfde80f 100644 --- a/source/tests/Test-PasswordHashSync.ps1 +++ b/source/tests/Test-PasswordHashSync.ps1 @@ -1,6 +1,5 @@ function Test-PasswordHashSync { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index a4f9a07..144a8d7 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -1,6 +1,5 @@ function Test-PasswordNeverExpirePolicy { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned [Parameter(Mandatory)] diff --git a/source/tests/Test-ReauthWithCode.ps1 b/source/tests/Test-ReauthWithCode.ps1 index 6adfd31..318bade 100644 --- a/source/tests/Test-ReauthWithCode.ps1 +++ b/source/tests/Test-ReauthWithCode.ps1 @@ -1,6 +1,5 @@ function Test-ReauthWithCode { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-ReportSecurityInTeams.ps1 b/source/tests/Test-ReportSecurityInTeams.ps1 index 9c889dd..aceaf1b 100644 --- a/source/tests/Test-ReportSecurityInTeams.ps1 +++ b/source/tests/Test-ReportSecurityInTeams.ps1 @@ -1,6 +1,5 @@ function Test-ReportSecurityInTeams { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index fea4a0f..99daa5a 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -1,6 +1,5 @@ function Test-RestrictCustomScripts { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Define your parameters here if needed ) diff --git a/source/tests/Test-RestrictExternalSharing.ps1 b/source/tests/Test-RestrictExternalSharing.ps1 index 04b00eb..0276204 100644 --- a/source/tests/Test-RestrictExternalSharing.ps1 +++ b/source/tests/Test-RestrictExternalSharing.ps1 @@ -1,6 +1,5 @@ function Test-RestrictExternalSharing { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-RestrictOutlookAddins.ps1 b/source/tests/Test-RestrictOutlookAddins.ps1 index 39f1ae6..6d28405 100644 --- a/source/tests/Test-RestrictOutlookAddins.ps1 +++ b/source/tests/Test-RestrictOutlookAddins.ps1 @@ -1,6 +1,5 @@ function Test-RestrictOutlookAddins { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters could include credentials or other necessary data diff --git a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 index fa7b256..d6d5235 100644 --- a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 +++ b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 @@ -1,6 +1,5 @@ function Test-RestrictStorageProvidersOutlook { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed diff --git a/source/tests/Test-RestrictTenantCreation.ps1 b/source/tests/Test-RestrictTenantCreation.ps1 index ede53c4..be6a148 100644 --- a/source/tests/Test-RestrictTenantCreation.ps1 +++ b/source/tests/Test-RestrictTenantCreation.ps1 @@ -1,6 +1,5 @@ function Test-RestrictTenantCreation { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeAttachmentsPolicy.ps1 b/source/tests/Test-SafeAttachmentsPolicy.ps1 index 18a90a2..3e5ad4f 100644 --- a/source/tests/Test-SafeAttachmentsPolicy.ps1 +++ b/source/tests/Test-SafeAttachmentsPolicy.ps1 @@ -1,6 +1,5 @@ function Test-SafeAttachmentsPolicy { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeAttachmentsTeams.ps1 b/source/tests/Test-SafeAttachmentsTeams.ps1 index 1fae789..f87a437 100644 --- a/source/tests/Test-SafeAttachmentsTeams.ps1 +++ b/source/tests/Test-SafeAttachmentsTeams.ps1 @@ -1,6 +1,5 @@ function Test-SafeAttachmentsTeams { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeLinksOfficeApps.ps1 b/source/tests/Test-SafeLinksOfficeApps.ps1 index aa30dbc..0e1cfed 100644 --- a/source/tests/Test-SafeLinksOfficeApps.ps1 +++ b/source/tests/Test-SafeLinksOfficeApps.ps1 @@ -1,6 +1,5 @@ function Test-SafeLinksOfficeApps { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-SharePointAADB2B.ps1 b/source/tests/Test-SharePointAADB2B.ps1 index c95e415..7dfde4d 100644 --- a/source/tests/Test-SharePointAADB2B.ps1 +++ b/source/tests/Test-SharePointAADB2B.ps1 @@ -1,6 +1,5 @@ function Test-SharePointAADB2B { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SharePointExternalSharingDomains.ps1 b/source/tests/Test-SharePointExternalSharingDomains.ps1 index ee309d7..848cba4 100644 --- a/source/tests/Test-SharePointExternalSharingDomains.ps1 +++ b/source/tests/Test-SharePointExternalSharingDomains.ps1 @@ -1,6 +1,5 @@ function Test-SharePointExternalSharingDomains { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SharePointGuestsItemSharing.ps1 b/source/tests/Test-SharePointGuestsItemSharing.ps1 index 75159b4..aade0b3 100644 --- a/source/tests/Test-SharePointGuestsItemSharing.ps1 +++ b/source/tests/Test-SharePointGuestsItemSharing.ps1 @@ -1,6 +1,5 @@ function Test-SharePointGuestsItemSharing { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SpamPolicyAdminNotify.ps1 b/source/tests/Test-SpamPolicyAdminNotify.ps1 index 8f100c7..8bb73bc 100644 --- a/source/tests/Test-SpamPolicyAdminNotify.ps1 +++ b/source/tests/Test-SpamPolicyAdminNotify.ps1 @@ -1,6 +1,5 @@ function Test-SpamPolicyAdminNotify { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-TeamsExternalAccess.ps1 b/source/tests/Test-TeamsExternalAccess.ps1 index aec7caa..059cdf7 100644 --- a/source/tests/Test-TeamsExternalAccess.ps1 +++ b/source/tests/Test-TeamsExternalAccess.ps1 @@ -1,6 +1,5 @@ function Test-TeamsExternalAccess { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-TeamsExternalFileSharing.ps1 b/source/tests/Test-TeamsExternalFileSharing.ps1 index 92ef78c..4004dcc 100644 --- a/source/tests/Test-TeamsExternalFileSharing.ps1 +++ b/source/tests/Test-TeamsExternalFileSharing.ps1 @@ -1,6 +1,5 @@ function Test-TeamsExternalFileSharing { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed From 4f8df29c7217afcd2dab910a39c943d7a1061753 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:35:25 -0500 Subject: [PATCH 31/45] add: Output type to tests. --- source/tests/Test-AntiPhishingPolicy.ps1 | 1 + source/tests/Test-AuditDisabledFalse.ps1 | 1 + source/tests/Test-AuditLogSearch.ps1 | 1 + source/tests/Test-BlockChannelEmails.ps1 | 1 + source/tests/Test-BlockMailForwarding.ps1 | 1 + source/tests/Test-BlockSharedMailboxSignIn.ps1 | 1 + source/tests/Test-CommonAttachmentFilter.ps1 | 1 + source/tests/Test-CustomerLockbox.ps1 | 1 + source/tests/Test-DialInBypassLobby.ps1 | 1 + source/tests/Test-DisallowInfectedFilesDownload.ps1 | 1 + source/tests/Test-EnableDKIM.ps1 | 1 + source/tests/Test-ExternalNoControl.ps1 | 1 + source/tests/Test-ExternalSharingCalendars.ps1 | 1 + source/tests/Test-GlobalAdminsCount.ps1 | 1 + source/tests/Test-GuestAccessExpiration.ps1 | 1 + source/tests/Test-GuestUsersBiweeklyReview.ps1 | 1 + source/tests/Test-IdentifyExternalEmail.ps1 | 1 + source/tests/Test-LinkSharingRestrictions.ps1 | 1 + source/tests/Test-MailTipsEnabled.ps1 | 1 + source/tests/Test-MailboxAuditingE3.ps1 | 1 + source/tests/Test-MailboxAuditingE5.ps1 | 1 + source/tests/Test-ManagedApprovedPublicGroups.ps1 | 1 + source/tests/Test-MeetingChatNoAnonymous.ps1 | 1 + source/tests/Test-ModernAuthExchangeOnline.ps1 | 1 + source/tests/Test-ModernAuthSharePoint.ps1 | 1 + source/tests/Test-NoAnonymousMeetingJoin.ps1 | 1 + source/tests/Test-NoAnonymousMeetingStart.ps1 | 1 + source/tests/Test-NoWhitelistDomains.ps1 | 1 + source/tests/Test-NotifyMalwareInternal.ps1 | 1 + source/tests/Test-OneDriveContentRestrictions.ps1 | 1 + source/tests/Test-OneDriveSyncRestrictions.ps1 | 1 + source/tests/Test-OrgOnlyBypassLobby.ps1 | 1 + source/tests/Test-OrganizersPresent.ps1 | 1 + source/tests/Test-PasswordHashSync.ps1 | 1 + source/tests/Test-PasswordNeverExpirePolicy.ps1 | 1 + source/tests/Test-ReauthWithCode.ps1 | 1 + source/tests/Test-ReportSecurityInTeams.ps1 | 1 + source/tests/Test-RestrictCustomScripts.ps1 | 1 + source/tests/Test-RestrictExternalSharing.ps1 | 1 + source/tests/Test-RestrictOutlookAddins.ps1 | 1 + source/tests/Test-RestrictStorageProvidersOutlook.ps1 | 1 + source/tests/Test-RestrictTenantCreation.ps1 | 1 + source/tests/Test-SafeAttachmentsPolicy.ps1 | 1 + source/tests/Test-SafeAttachmentsTeams.ps1 | 1 + source/tests/Test-SafeLinksOfficeApps.ps1 | 1 + source/tests/Test-SharePointAADB2B.ps1 | 1 + source/tests/Test-SharePointExternalSharingDomains.ps1 | 1 + source/tests/Test-SharePointGuestsItemSharing.ps1 | 1 + source/tests/Test-SpamPolicyAdminNotify.ps1 | 1 + source/tests/Test-TeamsExternalAccess.ps1 | 1 + source/tests/Test-TeamsExternalFileSharing.ps1 | 1 + 51 files changed, 51 insertions(+) diff --git a/source/tests/Test-AntiPhishingPolicy.ps1 b/source/tests/Test-AntiPhishingPolicy.ps1 index c36b20c..4e4de8c 100644 --- a/source/tests/Test-AntiPhishingPolicy.ps1 +++ b/source/tests/Test-AntiPhishingPolicy.ps1 @@ -1,5 +1,6 @@ function Test-AntiPhishingPolicy { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-AuditDisabledFalse.ps1 b/source/tests/Test-AuditDisabledFalse.ps1 index e8c4688..8a26323 100644 --- a/source/tests/Test-AuditDisabledFalse.ps1 +++ b/source/tests/Test-AuditDisabledFalse.ps1 @@ -1,5 +1,6 @@ function Test-AuditDisabledFalse { [CmdletBinding()] + [OutputType([CISAuditResult])] # Aligned param ( # Parameters can be added if needed diff --git a/source/tests/Test-AuditLogSearch.ps1 b/source/tests/Test-AuditLogSearch.ps1 index 2ffec8a..bbedbca 100644 --- a/source/tests/Test-AuditLogSearch.ps1 +++ b/source/tests/Test-AuditLogSearch.ps1 @@ -1,5 +1,6 @@ function Test-AuditLogSearch { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-BlockChannelEmails.ps1 b/source/tests/Test-BlockChannelEmails.ps1 index 623a882..5165b61 100644 --- a/source/tests/Test-BlockChannelEmails.ps1 +++ b/source/tests/Test-BlockChannelEmails.ps1 @@ -1,5 +1,6 @@ function Test-BlockChannelEmails { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index 692dda2..0ea1c1b 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -1,5 +1,6 @@ function Test-BlockMailForwarding { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-BlockSharedMailboxSignIn.ps1 b/source/tests/Test-BlockSharedMailboxSignIn.ps1 index 5561a3d..d1af582 100644 --- a/source/tests/Test-BlockSharedMailboxSignIn.ps1 +++ b/source/tests/Test-BlockSharedMailboxSignIn.ps1 @@ -1,5 +1,6 @@ function Test-BlockSharedMailboxSignIn { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-CommonAttachmentFilter.ps1 b/source/tests/Test-CommonAttachmentFilter.ps1 index 662529a..3341ca5 100644 --- a/source/tests/Test-CommonAttachmentFilter.ps1 +++ b/source/tests/Test-CommonAttachmentFilter.ps1 @@ -1,5 +1,6 @@ function Test-CommonAttachmentFilter { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-CustomerLockbox.ps1 b/source/tests/Test-CustomerLockbox.ps1 index b22773b..8396ffc 100644 --- a/source/tests/Test-CustomerLockbox.ps1 +++ b/source/tests/Test-CustomerLockbox.ps1 @@ -1,5 +1,6 @@ function Test-CustomerLockbox { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-DialInBypassLobby.ps1 b/source/tests/Test-DialInBypassLobby.ps1 index d9449b4..b7088ee 100644 --- a/source/tests/Test-DialInBypassLobby.ps1 +++ b/source/tests/Test-DialInBypassLobby.ps1 @@ -1,5 +1,6 @@ function Test-DialInBypassLobby { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-DisallowInfectedFilesDownload.ps1 b/source/tests/Test-DisallowInfectedFilesDownload.ps1 index 538e998..514dda7 100644 --- a/source/tests/Test-DisallowInfectedFilesDownload.ps1 +++ b/source/tests/Test-DisallowInfectedFilesDownload.ps1 @@ -1,5 +1,6 @@ function Test-DisallowInfectedFilesDownload { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-EnableDKIM.ps1 b/source/tests/Test-EnableDKIM.ps1 index db793c5..a6662e1 100644 --- a/source/tests/Test-EnableDKIM.ps1 +++ b/source/tests/Test-EnableDKIM.ps1 @@ -1,5 +1,6 @@ function Test-EnableDKIM { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-ExternalNoControl.ps1 b/source/tests/Test-ExternalNoControl.ps1 index 0fce827..1a8c82d 100644 --- a/source/tests/Test-ExternalNoControl.ps1 +++ b/source/tests/Test-ExternalNoControl.ps1 @@ -1,5 +1,6 @@ function Test-ExternalNoControl { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-ExternalSharingCalendars.ps1 b/source/tests/Test-ExternalSharingCalendars.ps1 index 3f0c7a6..ed5e941 100644 --- a/source/tests/Test-ExternalSharingCalendars.ps1 +++ b/source/tests/Test-ExternalSharingCalendars.ps1 @@ -1,5 +1,6 @@ function Test-ExternalSharingCalendars { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index 1a7525e..e0188f4 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -1,5 +1,6 @@ function Test-GlobalAdminsCount { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-GuestAccessExpiration.ps1 b/source/tests/Test-GuestAccessExpiration.ps1 index cef642f..986c8d7 100644 --- a/source/tests/Test-GuestAccessExpiration.ps1 +++ b/source/tests/Test-GuestAccessExpiration.ps1 @@ -1,5 +1,6 @@ function Test-GuestAccessExpiration { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-GuestUsersBiweeklyReview.ps1 b/source/tests/Test-GuestUsersBiweeklyReview.ps1 index 0aeb409..757c4d3 100644 --- a/source/tests/Test-GuestUsersBiweeklyReview.ps1 +++ b/source/tests/Test-GuestUsersBiweeklyReview.ps1 @@ -1,5 +1,6 @@ function Test-GuestUsersBiweeklyReview { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-IdentifyExternalEmail.ps1 b/source/tests/Test-IdentifyExternalEmail.ps1 index 6c43794..63bce34 100644 --- a/source/tests/Test-IdentifyExternalEmail.ps1 +++ b/source/tests/Test-IdentifyExternalEmail.ps1 @@ -1,5 +1,6 @@ function Test-IdentifyExternalEmail { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-LinkSharingRestrictions.ps1 b/source/tests/Test-LinkSharingRestrictions.ps1 index cc96c15..24cd22b 100644 --- a/source/tests/Test-LinkSharingRestrictions.ps1 +++ b/source/tests/Test-LinkSharingRestrictions.ps1 @@ -1,5 +1,6 @@ function Test-LinkSharingRestrictions { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-MailTipsEnabled.ps1 b/source/tests/Test-MailTipsEnabled.ps1 index c093dea..2ccf106 100644 --- a/source/tests/Test-MailTipsEnabled.ps1 +++ b/source/tests/Test-MailTipsEnabled.ps1 @@ -1,5 +1,6 @@ function Test-MailTipsEnabled { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index ad6364b..26e6379 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -1,5 +1,6 @@ function Test-MailboxAuditingE3 { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index 539b628..af40be6 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -1,5 +1,6 @@ function Test-MailboxAuditingE5 { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Parameters can be added if needed ) diff --git a/source/tests/Test-ManagedApprovedPublicGroups.ps1 b/source/tests/Test-ManagedApprovedPublicGroups.ps1 index 94512ff..073d540 100644 --- a/source/tests/Test-ManagedApprovedPublicGroups.ps1 +++ b/source/tests/Test-ManagedApprovedPublicGroups.ps1 @@ -1,5 +1,6 @@ function Test-ManagedApprovedPublicGroups { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-MeetingChatNoAnonymous.ps1 b/source/tests/Test-MeetingChatNoAnonymous.ps1 index 12764be..3524c6b 100644 --- a/source/tests/Test-MeetingChatNoAnonymous.ps1 +++ b/source/tests/Test-MeetingChatNoAnonymous.ps1 @@ -1,5 +1,6 @@ function Test-MeetingChatNoAnonymous { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-ModernAuthExchangeOnline.ps1 b/source/tests/Test-ModernAuthExchangeOnline.ps1 index 2c5c79e..8735fa4 100644 --- a/source/tests/Test-ModernAuthExchangeOnline.ps1 +++ b/source/tests/Test-ModernAuthExchangeOnline.ps1 @@ -1,5 +1,6 @@ function Test-ModernAuthExchangeOnline { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-ModernAuthSharePoint.ps1 b/source/tests/Test-ModernAuthSharePoint.ps1 index 990a64d..c56ef59 100644 --- a/source/tests/Test-ModernAuthSharePoint.ps1 +++ b/source/tests/Test-ModernAuthSharePoint.ps1 @@ -1,5 +1,6 @@ function Test-ModernAuthSharePoint { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-NoAnonymousMeetingJoin.ps1 b/source/tests/Test-NoAnonymousMeetingJoin.ps1 index 6a9336a..e28ebdb 100644 --- a/source/tests/Test-NoAnonymousMeetingJoin.ps1 +++ b/source/tests/Test-NoAnonymousMeetingJoin.ps1 @@ -1,5 +1,6 @@ function Test-NoAnonymousMeetingJoin { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-NoAnonymousMeetingStart.ps1 b/source/tests/Test-NoAnonymousMeetingStart.ps1 index 9820b84..5ffa6e2 100644 --- a/source/tests/Test-NoAnonymousMeetingStart.ps1 +++ b/source/tests/Test-NoAnonymousMeetingStart.ps1 @@ -1,5 +1,6 @@ function Test-NoAnonymousMeetingStart { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-NoWhitelistDomains.ps1 b/source/tests/Test-NoWhitelistDomains.ps1 index fe9ea6b..d51fdc1 100644 --- a/source/tests/Test-NoWhitelistDomains.ps1 +++ b/source/tests/Test-NoWhitelistDomains.ps1 @@ -1,5 +1,6 @@ function Test-NoWhitelistDomains { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-NotifyMalwareInternal.ps1 b/source/tests/Test-NotifyMalwareInternal.ps1 index eba1e84..1e466fb 100644 --- a/source/tests/Test-NotifyMalwareInternal.ps1 +++ b/source/tests/Test-NotifyMalwareInternal.ps1 @@ -1,5 +1,6 @@ function Test-NotifyMalwareInternal { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-OneDriveContentRestrictions.ps1 b/source/tests/Test-OneDriveContentRestrictions.ps1 index 5d10b50..0043aa9 100644 --- a/source/tests/Test-OneDriveContentRestrictions.ps1 +++ b/source/tests/Test-OneDriveContentRestrictions.ps1 @@ -1,5 +1,6 @@ function Test-OneDriveContentRestrictions { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-OneDriveSyncRestrictions.ps1 b/source/tests/Test-OneDriveSyncRestrictions.ps1 index b0af3df..436899a 100644 --- a/source/tests/Test-OneDriveSyncRestrictions.ps1 +++ b/source/tests/Test-OneDriveSyncRestrictions.ps1 @@ -1,5 +1,6 @@ function Test-OneDriveSyncRestrictions { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-OrgOnlyBypassLobby.ps1 b/source/tests/Test-OrgOnlyBypassLobby.ps1 index 9ad8958..735c86d 100644 --- a/source/tests/Test-OrgOnlyBypassLobby.ps1 +++ b/source/tests/Test-OrgOnlyBypassLobby.ps1 @@ -1,5 +1,6 @@ function Test-OrgOnlyBypassLobby { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-OrganizersPresent.ps1 b/source/tests/Test-OrganizersPresent.ps1 index 8e2fead..014d13d 100644 --- a/source/tests/Test-OrganizersPresent.ps1 +++ b/source/tests/Test-OrganizersPresent.ps1 @@ -1,5 +1,6 @@ function Test-OrganizersPresent { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-PasswordHashSync.ps1 b/source/tests/Test-PasswordHashSync.ps1 index dfde80f..83e6d9d 100644 --- a/source/tests/Test-PasswordHashSync.ps1 +++ b/source/tests/Test-PasswordHashSync.ps1 @@ -1,5 +1,6 @@ function Test-PasswordHashSync { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index 144a8d7..a4f9a07 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -1,5 +1,6 @@ function Test-PasswordNeverExpirePolicy { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned [Parameter(Mandatory)] diff --git a/source/tests/Test-ReauthWithCode.ps1 b/source/tests/Test-ReauthWithCode.ps1 index 318bade..6adfd31 100644 --- a/source/tests/Test-ReauthWithCode.ps1 +++ b/source/tests/Test-ReauthWithCode.ps1 @@ -1,5 +1,6 @@ function Test-ReauthWithCode { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-ReportSecurityInTeams.ps1 b/source/tests/Test-ReportSecurityInTeams.ps1 index aceaf1b..9c889dd 100644 --- a/source/tests/Test-ReportSecurityInTeams.ps1 +++ b/source/tests/Test-ReportSecurityInTeams.ps1 @@ -1,5 +1,6 @@ function Test-ReportSecurityInTeams { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 99daa5a..fea4a0f 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -1,5 +1,6 @@ function Test-RestrictCustomScripts { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Define your parameters here if needed ) diff --git a/source/tests/Test-RestrictExternalSharing.ps1 b/source/tests/Test-RestrictExternalSharing.ps1 index 0276204..04b00eb 100644 --- a/source/tests/Test-RestrictExternalSharing.ps1 +++ b/source/tests/Test-RestrictExternalSharing.ps1 @@ -1,5 +1,6 @@ function Test-RestrictExternalSharing { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-RestrictOutlookAddins.ps1 b/source/tests/Test-RestrictOutlookAddins.ps1 index 6d28405..39f1ae6 100644 --- a/source/tests/Test-RestrictOutlookAddins.ps1 +++ b/source/tests/Test-RestrictOutlookAddins.ps1 @@ -1,5 +1,6 @@ function Test-RestrictOutlookAddins { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters could include credentials or other necessary data diff --git a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 index d6d5235..fa7b256 100644 --- a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 +++ b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 @@ -1,5 +1,6 @@ function Test-RestrictStorageProvidersOutlook { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed diff --git a/source/tests/Test-RestrictTenantCreation.ps1 b/source/tests/Test-RestrictTenantCreation.ps1 index be6a148..ede53c4 100644 --- a/source/tests/Test-RestrictTenantCreation.ps1 +++ b/source/tests/Test-RestrictTenantCreation.ps1 @@ -1,5 +1,6 @@ function Test-RestrictTenantCreation { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeAttachmentsPolicy.ps1 b/source/tests/Test-SafeAttachmentsPolicy.ps1 index 3e5ad4f..18a90a2 100644 --- a/source/tests/Test-SafeAttachmentsPolicy.ps1 +++ b/source/tests/Test-SafeAttachmentsPolicy.ps1 @@ -1,5 +1,6 @@ function Test-SafeAttachmentsPolicy { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeAttachmentsTeams.ps1 b/source/tests/Test-SafeAttachmentsTeams.ps1 index f87a437..1fae789 100644 --- a/source/tests/Test-SafeAttachmentsTeams.ps1 +++ b/source/tests/Test-SafeAttachmentsTeams.ps1 @@ -1,5 +1,6 @@ function Test-SafeAttachmentsTeams { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-SafeLinksOfficeApps.ps1 b/source/tests/Test-SafeLinksOfficeApps.ps1 index 0e1cfed..aa30dbc 100644 --- a/source/tests/Test-SafeLinksOfficeApps.ps1 +++ b/source/tests/Test-SafeLinksOfficeApps.ps1 @@ -1,5 +1,6 @@ function Test-SafeLinksOfficeApps { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here if needed diff --git a/source/tests/Test-SharePointAADB2B.ps1 b/source/tests/Test-SharePointAADB2B.ps1 index 7dfde4d..c95e415 100644 --- a/source/tests/Test-SharePointAADB2B.ps1 +++ b/source/tests/Test-SharePointAADB2B.ps1 @@ -1,5 +1,6 @@ function Test-SharePointAADB2B { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SharePointExternalSharingDomains.ps1 b/source/tests/Test-SharePointExternalSharingDomains.ps1 index 848cba4..ee309d7 100644 --- a/source/tests/Test-SharePointExternalSharingDomains.ps1 +++ b/source/tests/Test-SharePointExternalSharingDomains.ps1 @@ -1,5 +1,6 @@ function Test-SharePointExternalSharingDomains { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SharePointGuestsItemSharing.ps1 b/source/tests/Test-SharePointGuestsItemSharing.ps1 index aade0b3..75159b4 100644 --- a/source/tests/Test-SharePointGuestsItemSharing.ps1 +++ b/source/tests/Test-SharePointGuestsItemSharing.ps1 @@ -1,5 +1,6 @@ function Test-SharePointGuestsItemSharing { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Define your parameters here diff --git a/source/tests/Test-SpamPolicyAdminNotify.ps1 b/source/tests/Test-SpamPolicyAdminNotify.ps1 index 8bb73bc..8f100c7 100644 --- a/source/tests/Test-SpamPolicyAdminNotify.ps1 +++ b/source/tests/Test-SpamPolicyAdminNotify.ps1 @@ -1,5 +1,6 @@ function Test-SpamPolicyAdminNotify { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added if needed diff --git a/source/tests/Test-TeamsExternalAccess.ps1 b/source/tests/Test-TeamsExternalAccess.ps1 index 059cdf7..aec7caa 100644 --- a/source/tests/Test-TeamsExternalAccess.ps1 +++ b/source/tests/Test-TeamsExternalAccess.ps1 @@ -1,5 +1,6 @@ function Test-TeamsExternalAccess { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be defined here if needed diff --git a/source/tests/Test-TeamsExternalFileSharing.ps1 b/source/tests/Test-TeamsExternalFileSharing.ps1 index 4004dcc..92ef78c 100644 --- a/source/tests/Test-TeamsExternalFileSharing.ps1 +++ b/source/tests/Test-TeamsExternalFileSharing.ps1 @@ -1,5 +1,6 @@ function Test-TeamsExternalFileSharing { [CmdletBinding()] + [OutputType([CISAuditResult])] param ( # Aligned # Parameters can be added here if needed From a5d26917d3d84caf42f256b91170d2d4034e46f8 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:51:54 -0500 Subject: [PATCH 32/45] add: paramters to get-requredmodules and updated public functions --- source/Private/Get-RequiredModule.ps1 | 45 ++++++++++++++++------ source/Public/Invoke-M365SecurityAudit.ps1 | 2 +- source/Public/Sync-CISExcelAndCsvData.ps1 | 7 ++++ 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/source/Private/Get-RequiredModule.ps1 b/source/Private/Get-RequiredModule.ps1 index fb426f5..b5b1c8d 100644 --- a/source/Private/Get-RequiredModule.ps1 +++ b/source/Private/Get-RequiredModule.ps1 @@ -1,15 +1,36 @@ function Get-RequiredModule { - return @( - @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0" }, - @{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Authentication" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Users" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Groups" }, - @{ 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" } + [CmdletBinding(DefaultParameterSetName = 'AuditFunction')] + param ( + [Parameter(Mandatory = $true, ParameterSetName = 'AuditFunction')] + [switch]$AuditFunction, + + [Parameter(Mandatory = $true, ParameterSetName = 'SyncFunction')] + [switch]$SyncFunction ) + + switch ($PSCmdlet.ParameterSetName) { + 'AuditFunction' { + return @( + @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0" }, + @{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182" }, + @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Authentication" }, + @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Users" }, + @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Groups" }, + @{ 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' { + return @( + @{ ModuleName = "ImportExcel"; RequiredVersion = "7.8.9" } + ) + } + default { + throw "Please specify either -AuditFunction or -SyncFunction switch." + } + } } diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index 1b7632c..a9b0046 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -65,7 +65,7 @@ function Invoke-M365SecurityAudit { } # Ensure required modules are installed if (!($NoModuleCheck)) { - $requiredModules = Get-RequiredModule + $requiredModules = Get-RequiredModule -AuditFunction foreach ($module in $requiredModules) { Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName } diff --git a/source/Public/Sync-CISExcelAndCsvData.ps1 b/source/Public/Sync-CISExcelAndCsvData.ps1 index 22d84b4..e07b725 100644 --- a/source/Public/Sync-CISExcelAndCsvData.ps1 +++ b/source/Public/Sync-CISExcelAndCsvData.ps1 @@ -49,6 +49,12 @@ function Sync-CISExcelAndCsvData { ) process { + # Verify ImportExcel module is available + $requiredModules = Get-RequiredModule -SyncFunction + foreach ($module in $requiredModules) { + Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName + } + # Merge Excel and CSV data $mergedData = Merge-CISExcelAndCsvData -ExcelPath $ExcelPath -WorksheetName $WorksheetName -CsvPath $CsvPath @@ -61,3 +67,4 @@ function Sync-CISExcelAndCsvData { } } } + From cbdb31c7c582885b5acdbd03dc62268587d86719 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:54:54 -0500 Subject: [PATCH 33/45] add: better output to 1.1.3 --- source/tests/Test-GlobalAdminsCount.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index e0188f4..0c71f28 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -15,15 +15,16 @@ function Test-GlobalAdminsCount { } process { - try { # 1.1.3 (L1) Ensure that between two and four global admins are designated # Retrieve global admin role and members $globalAdminRole = Get-MgDirectoryRole -Filter "RoleTemplateId eq '62e90394-69f5-4237-9190-012177145e10'" $globalAdmins = Get-MgDirectoryRoleMember -DirectoryRoleId $globalAdminRole.Id - $globalAdminCount = $globalAdmins.AdditionalProperties.Count - $globalAdminUsernames = ($globalAdmins | ForEach-Object { $_.AdditionalProperties["displayName"] }) -join ', ' + $globalAdminCount = $globalAdmins.Count + $globalAdminUsernames = ($globalAdmins | ForEach-Object { + "$($_.AdditionalProperties["displayName"]) ($($_.AdditionalProperties["userPrincipalName"]))" + }) -join ', ' # Prepare failure reasons and details based on compliance $failureReasons = if ($globalAdminCount -lt 2) { From 83ee6c2ac307c55570231f00817156fe5c6b5aad Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 12:02:16 -0500 Subject: [PATCH 34/45] add: New private function for csv/xlsx merge --- source/Private/Merge-CISExcelAndCsvData.ps1 | 18 ++----------- source/Private/New-MergedObject.ps1 | 20 ++++++++++++++ tests/Unit/Private/New-MergedObject.tests.ps1 | 27 +++++++++++++++++++ 3 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 source/Private/New-MergedObject.ps1 create mode 100644 tests/Unit/Private/New-MergedObject.tests.ps1 diff --git a/source/Private/Merge-CISExcelAndCsvData.ps1 b/source/Private/Merge-CISExcelAndCsvData.ps1 index bc09c22..7fd7cfc 100644 --- a/source/Private/Merge-CISExcelAndCsvData.ps1 +++ b/source/Private/Merge-CISExcelAndCsvData.ps1 @@ -16,27 +16,13 @@ function Merge-CISExcelAndCsvData { $import = Import-Excel -Path $ExcelPath -WorksheetName $WorksheetName $csvData = Import-Csv -Path $CsvPath - # Define a function to create a merged object - function CreateMergedObject($excelItem, $csvRow) { - $newObject = New-Object PSObject - - foreach ($property in $excelItem.PSObject.Properties) { - $newObject | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value - } - $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Connection' -Value $csvRow.Connection - $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Status' -Value $csvRow.Status - $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Details' -Value $csvRow.Details - $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_FailureReason' -Value $csvRow.FailureReason - return $newObject - } - # Iterate over each item in the imported Excel object and merge with CSV data $mergedData = foreach ($item in $import) { $csvRow = $csvData | Where-Object { $_.Rec -eq $item.'recommendation #' } if ($csvRow) { - CreateMergedObject -excelItem $item -csvRow $csvRow + New-MergedObject -ExcelItem $item -CsvRow $csvRow } else { - CreateMergedObject -excelItem $item -csvRow ([PSCustomObject]@{Connection=$null;Status=$null; Details=$null; FailureReason=$null }) + New-MergedObject -ExcelItem $item -CsvRow ([PSCustomObject]@{Connection=$null;Status=$null; Details=$null; FailureReason=$null }) } } diff --git a/source/Private/New-MergedObject.ps1 b/source/Private/New-MergedObject.ps1 new file mode 100644 index 0000000..4840d73 --- /dev/null +++ b/source/Private/New-MergedObject.ps1 @@ -0,0 +1,20 @@ +function New-MergedObject { + param ( + [Parameter(Mandatory = $true)] + [psobject]$ExcelItem, + + [Parameter(Mandatory = $true)] + [psobject]$CsvRow + ) + + $newObject = New-Object PSObject + + foreach ($property in $ExcelItem.PSObject.Properties) { + $newObject | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value + } + $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Connection' -Value $CsvRow.Connection + $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Status' -Value $CsvRow.Status + $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Details' -Value $CsvRow.Details + $newObject | Add-Member -MemberType NoteProperty -Name 'CSV_FailureReason' -Value $CsvRow.FailureReason + return $newObject +} diff --git a/tests/Unit/Private/New-MergedObject.tests.ps1 b/tests/Unit/Private/New-MergedObject.tests.ps1 new file mode 100644 index 0000000..4a2aa69 --- /dev/null +++ b/tests/Unit/Private/New-MergedObject.tests.ps1 @@ -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' + } + } + } +} + From c0222ef3bcd536d6b6b37fefb05da3749efbb482 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 12:11:01 -0500 Subject: [PATCH 35/45] add:comment-help block back to public function --- source/Public/Invoke-M365SecurityAudit.ps1 | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index a9b0046..c3b49ba 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -1,3 +1,64 @@ +<# + .SYNOPSIS + Invokes a security audit for Microsoft 365 environments. + .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. + .PARAMETER DomainName + The domain name of the Microsoft 365 environment. This parameter is mandatory. + .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 + Specifies the profile level (L1 or L2) for the audit. This parameter is optional and can be combined with the ELevel parameter. + .PARAMETER IncludeIG1 + If specified, includes tests where IG1 is true. + .PARAMETER IncludeIG2 + If specified, includes tests where IG2 is true. + .PARAMETER IncludeIG3 + If specified, includes tests where IG3 is true. + .PARAMETER IncludeRecommendation + Specifies specific recommendations to include in the audit. Accepts an array of recommendation numbers. + .PARAMETER SkipRecommendation + Specifies specific recommendations to exclude from the audit. Accepts an array of recommendation numbers. + .PARAMETER DoNotConnect + If specified, the cmdlet will not establish a connection to Microsoft 365 services. + .PARAMETER DoNotDisconnect + If specified, the cmdlet will not disconnect from Microsoft 365 services after execution. + .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" + + Performs a security audit for the E5 level and L1 profile in the specified Microsoft 365 environment. + .EXAMPLE + PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -IncludeIG1 + + Performs an audit including all tests where IG1 is true. + .EXAMPLE + PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -SkipRecommendation '1.1.3', '2.1.1' + + Performs an audit while excluding specific recommendations 1.1.3 and 2.1.1. + .EXAMPLE + PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" + PS> $auditResults | Export-Csv -Path "auditResults.csv" -NoTypeInformation + + Captures the audit results into a variable and exports them to a CSV file. + .INPUTS + None. You cannot pipe objects to Invoke-M365SecurityAudit. + .OUTPUTS + CISAuditResult[] + The cmdlet returns an array of CISAuditResult objects representing the results of the security audit. + .NOTES + - This module is based on CIS benchmarks. + - Governed by the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. + - Commercial use is not permitted. This module cannot be sold or used for commercial purposes. + - Modifications and sharing are allowed under the same license. + - For full license details, visit: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en + - Register for CIS Benchmarks at: https://www.cisecurity.org/cis-benchmarks + .LINK + https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit +#> function Invoke-M365SecurityAudit { [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')] [OutputType([CISAuditResult[]])] From a5dc7f1ebd99ffdebb970832feee151c17d897b9 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 12:38:47 -0500 Subject: [PATCH 36/45] docs: update help --- README.md | Bin 10179 -> 14396 bytes docs/index.html | Bin 30419 -> 48876 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/README.md b/README.md index f57576e7719c522528d7c1b615abf669767e5a15..b277981b2a0ddb1d971b0b2010ee1e0387b78004 100644 GIT binary patch literal 14396 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 PWPMs4Mf36Qexm;ZGoi1F literal 10179 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 diff --git a/docs/index.html b/docs/index.html index acf3db06ba346b690179eb6e7c6a8bdf6835ef1f..8cea2a9ff6ad08f8bdedfae44199fd11ac86a254 100644 GIT binary patch literal 48876 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 literal 30419 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 From 5871294210ee1f740aa63d390539a35ee2c840ec Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 13:01:39 -0500 Subject: [PATCH 37/45] add: progress bar and surpressed verbose progress. --- source/Private/Invoke-TestFunction.ps1 | 2 +- source/Public/Invoke-M365SecurityAudit.ps1 | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/source/Private/Invoke-TestFunction.ps1 b/source/Private/Invoke-TestFunction.ps1 index 2dea2d0..d9a5997 100644 --- a/source/Private/Invoke-TestFunction.ps1 +++ b/source/Private/Invoke-TestFunction.ps1 @@ -17,7 +17,7 @@ function Invoke-TestFunction { } # Use splatting to pass parameters - Write-Host "Running $functionName..." + Write-Verbose "Running $functionName..." try { $result = & $functionName @paramList # Assuming each function returns an array of CISAuditResult or a single CISAuditResult diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index c3b49ba..93c7eb9 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -166,8 +166,14 @@ function Invoke-M365SecurityAudit { $testsFolderPath = Join-Path -Path $PSScriptRoot -ChildPath "tests" $testFiles = Get-ChildItem -Path $testsFolderPath -Filter "Test-*.ps1" | Where-Object { $testsToLoad -contains $_.BaseName } + + $totalTests = $testFiles.Count + $currentTestIndex = 0 + # Import the test functions $testFiles | ForEach-Object { + $currentTestIndex++ + Write-Progress -Activity "Loading Test Scripts" -Status "Loading $($currentTestIndex) of $($totalTests): $($_.Name)" -PercentComplete (($currentTestIndex / $totalTests) * 100) Try { # Dot source the test function . $_.FullName @@ -179,8 +185,11 @@ function Invoke-M365SecurityAudit { } } + $currentTestIndex = 0 # Execute each test function from the prepared list foreach ($testFunction in $testFiles) { + $currentTestIndex++ + 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 @@ -201,3 +210,4 @@ function Invoke-M365SecurityAudit { return $allAuditResults.ToArray() | Sort-Object -Property Rec } } + From 4ab5affc9fc1105b7d09b3ec3642c2c315cd467c Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 13:26:13 -0500 Subject: [PATCH 38/45] fix: script analyzer reccomendations. --- CHANGELOG.md | 2 +- .../Test-MailboxAuditingE3_6.1.2_E3L1_IG1_IG2_IG3.ps1 | 4 ++-- .../Test-MailboxAuditingE5_6.1.3_E5L1_IG1_IG2_IG3.ps1 | 4 ++-- .../{Format-MissingActions.ps1 => Format-MissingAction.ps1} | 2 +- source/Private/Get-RequiredModule.ps1 | 1 + source/Private/Update-CISExcelWorksheet.ps1 | 2 +- .../{Update-WorksheetCells.ps1 => Update-WorksheetCell.ps1} | 2 +- source/Public/Get-AdminRoleUserLicense.ps1 | 2 ++ source/tests/Test-MailboxAuditingE3.ps1 | 2 +- source/tests/Test-MailboxAuditingE5.ps1 | 2 +- 10 files changed, 13 insertions(+), 10 deletions(-) rename source/Private/{Format-MissingActions.ps1 => Format-MissingAction.ps1} (94%) rename source/Private/{Update-WorksheetCells.ps1 => Update-WorksheetCell.ps1} (95%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59cf0c4..60c65fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ The format is based on and uses the types of changes according to [Keep a Change - Added a new private function `Measure-AuditResult` to calculate and display audit results. - Enhanced error logging to capture failed test details and display them at the end of the audit. - Added a private function `Get-RequiredModule` to initialize the `$requiredModules` variable for better code organization in the main script. -- Updated `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` functions to use `Format-MissingActions` for structuring missing actions into a pipe-separated table format. +- Updated `Test-MailboxAuditingE3` and `Test-MailboxAuditingE5` functions to use `Format-MissingAction` for structuring missing actions into a pipe-separated table format. - Added more verbose logging to `Test-BlockMailForwarding` and improved error handling for better troubleshooting. - Improved `Test-RestrictCustomScripts` to handle long URL lengths better by extracting and replacing common hostnames, and provided detailed output. - Added sorting to output. diff --git a/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE3_6.1.2_E3L1_IG1_IG2_IG3.ps1 b/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE3_6.1.2_E3L1_IG1_IG2_IG3.ps1 index abce35b..62a5675 100644 --- a/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE3_6.1.2_E3L1_IG1_IG2_IG3.ps1 +++ b/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE3_6.1.2_E3L1_IG1_IG2_IG3.ps1 @@ -60,7 +60,7 @@ function Test-MailboxAuditingE3_6.1.2_E3L1_IG1_IG2_IG3 { } if ($missingActions) { - $formattedActions = Format-MissingActions $missingActions + $formattedActions = Format-MissingAction $missingActions $allFailures += "$userUPN`: AuditEnabled - True; $formattedActions" } # Mark the user as processed @@ -83,7 +83,7 @@ function Test-MailboxAuditingE3_6.1.2_E3L1_IG1_IG2_IG3 { } } -function Format-MissingActions { +function Format-MissingAction { param ([array]$missingActions) $actionGroups = @{ diff --git a/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE5_6.1.3_E5L1_IG1_IG2_IG3.ps1 b/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE5_6.1.3_E5L1_IG1_IG2_IG3.ps1 index 1dd6b92..5525a67 100644 --- a/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE5_6.1.3_E5L1_IG1_IG2_IG3.ps1 +++ b/helpers/CIS 365 v3.0.0 Controls/Test-MailboxAuditingE5_6.1.3_E5L1_IG1_IG2_IG3.ps1 @@ -60,7 +60,7 @@ function Test-MailboxAuditingE5_6.1.3_E5L1_IG1_IG2_IG3 { } if ($missingActions) { - $formattedActions = Format-MissingActions $missingActions + $formattedActions = Format-MissingAction $missingActions $allFailures += "$userUPN`: AuditEnabled - True; $formattedActions" } else { @@ -92,7 +92,7 @@ function Test-MailboxAuditingE5_6.1.3_E5L1_IG1_IG2_IG3 { } } -function Format-MissingActions { +function Format-MissingAction { param ([array]$missingActions) $actionGroups = @{ diff --git a/source/Private/Format-MissingActions.ps1 b/source/Private/Format-MissingAction.ps1 similarity index 94% rename from source/Private/Format-MissingActions.ps1 rename to source/Private/Format-MissingAction.ps1 index f6fd0bf..1932fb1 100644 --- a/source/Private/Format-MissingActions.ps1 +++ b/source/Private/Format-MissingAction.ps1 @@ -1,4 +1,4 @@ -function Format-MissingActions { +function Format-MissingAction { param ([array]$missingActions) $actionGroups = @{ diff --git a/source/Private/Get-RequiredModule.ps1 b/source/Private/Get-RequiredModule.ps1 index b5b1c8d..ffa65fc 100644 --- a/source/Private/Get-RequiredModule.ps1 +++ b/source/Private/Get-RequiredModule.ps1 @@ -1,5 +1,6 @@ function Get-RequiredModule { [CmdletBinding(DefaultParameterSetName = 'AuditFunction')] + [OutputType([PSCustomObject])] param ( [Parameter(Mandatory = $true, ParameterSetName = 'AuditFunction')] [switch]$AuditFunction, diff --git a/source/Private/Update-CISExcelWorksheet.ps1 b/source/Private/Update-CISExcelWorksheet.ps1 index 6de5747..a0d7ae1 100644 --- a/source/Private/Update-CISExcelWorksheet.ps1 +++ b/source/Private/Update-CISExcelWorksheet.ps1 @@ -25,7 +25,7 @@ function Update-CISExcelWorksheet { # Update the worksheet with the provided data - Update-WorksheetCells -Worksheet $worksheet -Data $Data -StartingRowIndex $StartingRowIndex + Update-WorksheetCell -Worksheet $worksheet -Data $Data -StartingRowIndex $StartingRowIndex # Save and close the Excel package Close-ExcelPackage $excelPackage diff --git a/source/Private/Update-WorksheetCells.ps1 b/source/Private/Update-WorksheetCell.ps1 similarity index 95% rename from source/Private/Update-WorksheetCells.ps1 rename to source/Private/Update-WorksheetCell.ps1 index eae857f..622f963 100644 --- a/source/Private/Update-WorksheetCells.ps1 +++ b/source/Private/Update-WorksheetCell.ps1 @@ -1,4 +1,4 @@ - function Update-WorksheetCells { + function Update-WorksheetCell { param ( $Worksheet, $Data, diff --git a/source/Public/Get-AdminRoleUserLicense.ps1 b/source/Public/Get-AdminRoleUserLicense.ps1 index fa2a49a..9cd86c3 100644 --- a/source/Public/Get-AdminRoleUserLicense.ps1 +++ b/source/Public/Get-AdminRoleUserLicense.ps1 @@ -25,6 +25,8 @@ https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Get-AdminRoleUserLicense #> function Get-AdminRoleUserLicense { + # Set output type to System.Collections.ArrayList + [OutputType([System.Collections.ArrayList])] [CmdletBinding()] param ( [Parameter(Mandatory = $false)] diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index 26e6379..ca9efcd 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -49,7 +49,7 @@ function Test-MailboxAuditingE3 { } if ($missingActions.Count -gt 0) { - $formattedActions = Format-MissingActions -missingActions $missingActions + $formattedActions = Format-MissingAction -missingActions $missingActions $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" } } diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index af40be6..b21f6a2 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -49,7 +49,7 @@ function Test-MailboxAuditingE5 { } if ($missingActions.Count -gt 0) { - $formattedActions = Format-MissingActions -missingActions $missingActions + $formattedActions = Format-MissingAction -missingActions $missingActions $allFailures += "$userUPN|True|$($formattedActions.Admin)|$($formattedActions.Delegate)|$($formattedActions.Owner)" } } From 7a9d2885f360e7adc68fd670bb41c6ff948c37fe Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 13:29:48 -0500 Subject: [PATCH 39/45] fix: script analyzer reccomendations. --- source/Private/Get-RequiredModule.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Private/Get-RequiredModule.ps1 b/source/Private/Get-RequiredModule.ps1 index ffa65fc..015036b 100644 --- a/source/Private/Get-RequiredModule.ps1 +++ b/source/Private/Get-RequiredModule.ps1 @@ -1,6 +1,6 @@ function Get-RequiredModule { [CmdletBinding(DefaultParameterSetName = 'AuditFunction')] - [OutputType([PSCustomObject])] + [OutputType([System.Object[]])] param ( [Parameter(Mandatory = $true, ParameterSetName = 'AuditFunction')] [switch]$AuditFunction, From ef55447e677aae31aa4eed9483206df8b1c67061 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:03:55 -0500 Subject: [PATCH 40/45] docs:update help --- README.md | Bin 14396 -> 17452 bytes docs/index.html | Bin 48876 -> 54652 bytes source/Private/Merge-CISExcelAndCsvData.ps1 | 23 +++++++++----- source/Public/Sync-CISExcelAndCsvData.ps1 | 33 +++++++++++++++----- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b277981b2a0ddb1d971b0b2010ee1e0387b78004..f5830579b579c890d8f06319c13d1a86155469c6 100644 GIT binary patch literal 17452 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 delta 2583 zcmb_dPiUKE7=MB;%sOLfm!{2@_$FPOG)-er(2kj;OV+s#Myo9%ww1*-S-WOSNYX#^ zusj$NiDtZ-!4#b0q3=f_>_?cPGG{J&%Xwvt{UG7{Lp+d<8kr5 z#5??bxSt=!;vCB!=as}X|2+9p`}|`lit|O@4=a6-MLqo8t8RWYcD((3Z`|KL7bDg= ztz|<~3EYj}bEhQ6MPA4q<=YcUeg0FKdpz+r@21c5Z*EUxk#5orx3mHdO6r{lS7B^W-gdI?PtgDj=DJ>Iyzfvc~O8{29jQgI?2mhAx(i8Ayeqvpc}mT zRN$F5p_~uh`+;t&r0YhYbR3v#EPCKaiwf(GjEaW(+&^$l_* zbdBrTa0}(?VMKJ-*pa$Me-&|hN52jXRl3SwkB$u5i`>%IR4wG9{3I4@6ww~isk(18 zC&G}lj)D*A&@J5UT(!L8opfXeK^Yx=4N~#d;kgWZdG0i!FfZ6Og9-;b#IBO@{l3YU zD;ml+fE9EBZ4O}H6A(Y1I>Y;vq3%WtxOE1xs65v6kkrGdqozl0X(~)~KC>#4P4Z`duDPTF|{E z;1n&vX&Ga&$$Lp3&pf|??RY*CMvh{)j(!q8S72i;@B~gJB(O_iK9dPG!eqr*gudRg z6o%)6ds9Jr(5ppD0+h*)4byYfN0;?aPM6>hBaf@|BU6O5j4TvI8f|VZClQFHc%~5| zJ)w(^EZz2yP^3p1qSZCJkXa;4YmS*5oZp}>BR)IkJ!E?3r(fW|`lBaKIVRrXR8fi) z|CD+C-_+!d|F#n*t(vF0xIXszvrINl-rl7nK=a#WouY_@X#fjL^%6U Z{`1HF+t)rfi}J`Yds5qSc2DRQ`y1I}E6o4^ diff --git a/docs/index.html b/docs/index.html index 8cea2a9ff6ad08f8bdedfae44199fd11ac86a254..20f1530eee240fde10bcc40679aeb0333c3cfe43 100644 GIT binary patch delta 5602 zcmc&&TWr%+7(X2s0Ywlf7spJyE5mhTD-+nFq3nW_F$d$KY)jU4W7Mtf*2@MFtVE;e z5;2|^BckAg4<-`yZ-^lVh~dGgk!gH11`^-o0euGb_dBPjw{_!^xTR_T?YVsC`@Zvi zzwh_;=AFFTpUrvq_r)7Uo!B61)TjH4KmTozJtcGHE$7@#Eg~pJMMw;aei0E4;l(?G z?>-R|Vc{21aYT*AM4$TQ5C^e3EKk<2TJ9E4iCWC|D;a*Q56PXyB?;M&$TN*Kai0ia z=MdIJv2qyCu$F*vbDj?p1DFeA_K=bm!C9mDb~jymp)a-V!^#k}aNrb5;69$^lP`xB zmk(oA81Dc^qIicfTZuI-N+&P08^Z1}5s}A>?A;;g=fLUQJn8mL9C;FV^~F<{7O47{Z^I3ZlFL-+>!a*8@+;p{T>|5{*!kOQ=E{o;XMjMoZ)`J66x@ zhM-RQVw*GZZAni-xf&BLu^*yoW(&+VV+~0+ghfD}F5U9bVzEfzEkAB_-}OxAVwY$V ztx%koI|MD9^26T8p=a@IXe0kVuwq`d^1!tn`7`Ycb$ZP#p1yJp?|wEcAMLIvafni+ zT~yQ~n4>Dym@=J+v{F1dK3m!q_m|F;cGl_Ah4bXafgk0WV>Pb5VmFe5NJa!QNJhj8 zA`yuV#DhL0FjCpNeEbKSyxD%0TOaOA<+!|dEMLA?zoKATn9Y8gnq6L?q^cP5^6~ObA;>p)NxY>U8Zmw9 zn?^GSFpp5xtDp*~E`OGG`BCp`J1a*vhF4lQcAd0g`a7C1Fr5i3Ep)0MN3%HaQy~z( zuY+;K02DQRwxUS>ujV+@@DJzZG;7~koBU_*mo!TretoTn!0m(5^r*QTKBI{W!-~h+ z$%?jJ8RJ(oOsg2i>8Uj~dEt#`<<{&FXhO4efzNQkM( zOt1$Xd!_xq-mh9sDYg2=;k0XI3NcCpN^MPIl1X&`s&%z3lE3Y^l(^_(dBFYX5^@M~ z9aC;?u1r^3C)fCU*$7|B6TGR7(`&vW@Eb~ekdwx7~PmSl;9XeNCGn@Np= z5aGi?Z#m1Wvjr0Z4&s7%94X{swKkT7iL8T{^?aXx@WAAQ$%J^^AjD;(k>-|Efsw#W z(HP6D8NtnxyJ{90z)T-T2oc%VTg@+R%R>rnw)V9&=E;e^`SP8iF01Fwi#B<^VS_w3 zUTn42?6z&v6wL!Mnl$fL!YDMVDjYe}9;GfJFG-N4Yy8RlY4*zM6U*i3c;OZ*8&OJX z2*@lLG;<32Zhbz!BrndRb*`mbYw~Y0r=F5=(nBPF@TY#c@Z1g$5?sUT`pJrWRS#h* zLql9STN7wa^2sU#co{nFfuA%d=!KQ0aJax;xx%dG5k45gg5m;;AX}wpJoxQb4UI!= zgn}EOLJRikSPP1Hio5Gt)QaVd3UYa%oHu=v&XgGDS&yiqx!VX*ARQMKHt&b-^AV zK50W$B5XFA zQ4xk(Aym%UNMgKDtw~AE+>=Rn3KuBC2yyaMZ~j7VCi^OsXX~ot?QqrPKL@hCK;Ic$ zO=W}$K+@4nerLj3v%G93NHY`RD@Q`B?#`R#jrx1wXB>m}o@pd3Z?Uh ziu79kv^?Ed%YRaIbPdj6bS1K|Bdr6UPSc~XxCy+Ca1jPrxKNoRz-U56J1k^QGQ(5R zm}x74g6lQ7v_Z-qaU>3L{i&V}rj&5a%h^tFdjt5!K0FgWrR9BQY>wi9OFuZLp232Z^7ghr ztQCRzAcrGMt@c>g+*O_=bY-~0I@>*xC!1frWS!sjtxcXgas^+m*yP)-D<<=30s194qFqa))xH-T)4fG delta 3263 zcmc&$U1%It6h4~<6m6R34~_Y8wy9lcn{7>m)7Q!4sE4{~5AI#mb@kVO`d8D>-qfTHS=)W4C* zzg}p*Y7%ZB@oc5{x=YUBpdi^W_V}=sIC+~oY-|cSU)!-&> zZx8Pg9CIofWm}<4VO55va4(N(QpKARq#QiiWS9GS*m%alMHaRtVqs6>x4=r8Qn>U? z0`C_ojQPWeS>9^?B48|wH7fFBrO+)bdWgWWZ2<(zT6c#VtN;JKBZMjJ^irMydHG-L#!hl3#rvy~;ijjw6Jo$@Z0oYMC zHXK;Uy*LssGc=EB4a86(?&E+a^V-d%f|SBjPKBk{3$qe>7IPT{8pZ#dvMl+T#2aJL z4Y5ID@|RV!^ZubiK-P?HbR@UqCo53ie=#re7oqigN zHR60X`gMTMUAb$V+rqQpU(1`1Dy%RiA=z=AxePxlOn}<1@QX2tTm(pxT1l#68hicn zmj?Ujdc^rlPzu|n%2ZvE6cvl>zSvy+Rjj4XRlYI;>sM|o5Phju+i>oeB%v#*dPPcJ z7pRxGid_saY4C6yJEW*x($gq#d0x}Sd_DhUn>Pi%#PL+;j&9v{(r^*mJIt16E*fH$Y zCz*yOH6dyusw4CIY||e)KrcKIZR_klcvri$ZkUA z(q+P%MfYHmp3ovFy&+;ZgUdEGEb(fWS(p^{loQvWHE9aUI?7>NqW*{#VEi$g$?MkW$K zo8zB*pFQ*Oey8uFUzAeg6tASy7HvWFT1-b^JxwF9X?i$}k(|UQuuAr?ujOLL;2T8T z>IZiA=8aogx8gJzM5}%u%tVYeG6Ka X`z~CDJWq3>tDX1tpK`{owRZdm;L*}g diff --git a/source/Private/Merge-CISExcelAndCsvData.ps1 b/source/Private/Merge-CISExcelAndCsvData.ps1 index 7fd7cfc..0922c9b 100644 --- a/source/Private/Merge-CISExcelAndCsvData.ps1 +++ b/source/Private/Merge-CISExcelAndCsvData.ps1 @@ -1,5 +1,5 @@ function Merge-CISExcelAndCsvData { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'CsvInput')] param ( [Parameter(Mandatory = $true)] [string]$ExcelPath, @@ -7,16 +7,25 @@ function Merge-CISExcelAndCsvData { [Parameter(Mandatory = $true)] [string]$WorksheetName, - [Parameter(Mandatory = $true)] - [string]$CsvPath + [Parameter(Mandatory = $true, ParameterSetName = 'CsvInput')] + [string]$CsvPath, + + [Parameter(Mandatory = $true, ParameterSetName = 'ObjectInput')] + [CISAuditResult[]]$AuditResults ) process { - # Import data from Excel and CSV + # Import data from Excel $import = Import-Excel -Path $ExcelPath -WorksheetName $WorksheetName - $csvData = Import-Csv -Path $CsvPath - # Iterate over each item in the imported Excel object and merge with CSV data + # Import data from CSV or use provided object + $csvData = if ($PSCmdlet.ParameterSetName -eq 'CsvInput') { + Import-Csv -Path $CsvPath + } else { + $AuditResults + } + + # Iterate over each item in the imported Excel object and merge with CSV data or audit results $mergedData = foreach ($item in $import) { $csvRow = $csvData | Where-Object { $_.Rec -eq $item.'recommendation #' } if ($csvRow) { @@ -29,4 +38,4 @@ function Merge-CISExcelAndCsvData { # Return the merged data return $mergedData } -} +} \ No newline at end of file diff --git a/source/Public/Sync-CISExcelAndCsvData.ps1 b/source/Public/Sync-CISExcelAndCsvData.ps1 index e07b725..4b79249 100644 --- a/source/Public/Sync-CISExcelAndCsvData.ps1 +++ b/source/Public/Sync-CISExcelAndCsvData.ps1 @@ -1,14 +1,16 @@ <# .SYNOPSIS - Synchronizes data between an Excel file and a CSV file and optionally updates the Excel worksheet. + Synchronizes data between an Excel file and either a CSV file or an output object from Invoke-M365SecurityAudit, and optionally updates the Excel worksheet. .DESCRIPTION - The Sync-CISExcelAndCsvData function merges data from a specified Excel file and a CSV file based on a common key. It can also update the Excel worksheet with the merged data. This function is particularly useful for updating Excel records with additional data from a CSV file while preserving the original formatting and structure of the Excel worksheet. + The Sync-CISExcelAndCsvData function merges data from a specified Excel file with data from either a CSV file or an output object from Invoke-M365SecurityAudit based on a common key. It can also update the Excel worksheet with the merged data. This function is particularly useful for updating Excel records with additional data from a CSV file or audit results while preserving the original formatting and structure of the Excel worksheet. .PARAMETER ExcelPath The path to the Excel file that contains the original data. This parameter is mandatory. .PARAMETER WorksheetName The name of the worksheet within the Excel file that contains the data to be synchronized. This parameter is mandatory. .PARAMETER CsvPath - The path to the CSV file containing data to be merged with the Excel data. This parameter is mandatory. + The path to the CSV file containing data to be merged with the Excel data. This parameter is mandatory when using the CsvInput parameter set. + .PARAMETER AuditResults + An array of CISAuditResult objects from Invoke-M365SecurityAudit to be merged with the Excel data. This parameter is mandatory when using the ObjectInput parameter set. .PARAMETER SkipUpdate If specified, the function will return the merged data object without updating the Excel worksheet. This is useful for previewing the merged data. .EXAMPLE @@ -17,6 +19,14 @@ .EXAMPLE PS> $mergedData = Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -CsvPath "path\to\data.csv" -SkipUpdate Retrieves the merged data object for preview without updating the Excel worksheet. + .EXAMPLE + PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://tenant-admin.url" -DomainName "example.com" + PS> Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -AuditResults $auditResults + Merges data from the audit results into 'excel.xlsx' on the 'DataSheet' worksheet and updates the worksheet with the merged data. + .EXAMPLE + PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://tenant-admin.url" -DomainName "example.com" + PS> $mergedData = Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -AuditResults $auditResults -SkipUpdate + Retrieves the merged data object for preview without updating the Excel worksheet. .INPUTS None. You cannot pipe objects to Sync-CISExcelAndCsvData. .OUTPUTS @@ -30,8 +40,9 @@ https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Sync-CISExcelAndCsvData #> + function Sync-CISExcelAndCsvData { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'CsvInput')] param ( [Parameter(Mandatory = $true)] [ValidateScript({ Test-Path $_ })] @@ -40,10 +51,13 @@ function Sync-CISExcelAndCsvData { [Parameter(Mandatory = $true)] [string]$WorksheetName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, ParameterSetName = 'CsvInput')] [ValidateScript({ Test-Path $_ })] [string]$CsvPath, + [Parameter(Mandatory = $true, ParameterSetName = 'ObjectInput')] + [CISAuditResult[]]$AuditResults, + [Parameter(Mandatory = $false)] [switch]$SkipUpdate ) @@ -55,8 +69,12 @@ function Sync-CISExcelAndCsvData { Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName } - # Merge Excel and CSV data - $mergedData = Merge-CISExcelAndCsvData -ExcelPath $ExcelPath -WorksheetName $WorksheetName -CsvPath $CsvPath + # Merge Excel and CSV data or Audit Results + if ($PSCmdlet.ParameterSetName -eq 'CsvInput') { + $mergedData = Merge-CISExcelAndCsvData -ExcelPath $ExcelPath -WorksheetName $WorksheetName -CsvPath $CsvPath + } else { + $mergedData = Merge-CISExcelAndCsvData -ExcelPath $ExcelPath -WorksheetName $WorksheetName -AuditResults $AuditResults + } # Output the merged data if the user chooses to skip the update if ($SkipUpdate) { @@ -68,3 +86,4 @@ function Sync-CISExcelAndCsvData { } } + From b70da1845f01edb29b7d0403871addf4c4f8f19f Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:10:55 -0500 Subject: [PATCH 41/45] addL paramter validation to main function --- source/Public/Invoke-M365SecurityAudit.ps1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index 93c7eb9..aa22711 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -63,10 +63,12 @@ function Invoke-M365SecurityAudit { [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')] [OutputType([CISAuditResult[]])] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, HelpMessage = "The SharePoint tenant admin URL, which should end with '-admin.sharepoint.com'.")] + [ValidatePattern('^https://[a-zA-Z0-9-]+-admin\.sharepoint\.com$')] [string]$TenantAdminUrl, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, HelpMessage = "The domain name of your organization, e.g., 'example.com'.")] + [ValidatePattern('^[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$')] [string]$DomainName, # E-Level with optional ProfileLevel selection From f7b87ebc78f93311cf68df90b79fa02cf726dfd2 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:25:00 -0500 Subject: [PATCH 42/45] test: update workflow --- .github/workflows/powershell.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/powershell.yml b/.github/workflows/powershell.yml index 94c9bc1..200e585 100644 --- a/.github/workflows/powershell.yml +++ b/.github/workflows/powershell.yml @@ -36,10 +36,25 @@ jobs: with: # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. - path: .\ + path: | + .\source\Classes + .\source\helper + .\source\Private + .\source\Public + .\source\tests recurse: true # Include your own basic security rules. Removing this option will run all the rules - includeRule: '"PSAvoidGlobalAliases", "PSAvoidUsingConvertToSecureStringWithPlainText"' + includeRule: | + "PSAvoidGlobalAliases", + "PSAvoidUsingConvertToSecureStringWithPlainText", + "PSAvoidUsingPlainTextForPassword", + "PSAvoidUsingInvokeExpression", + "PSUseApprovedVerbs", + "PSAvoidUsingPositionalParameters", + "PSAvoidUsingEmptyCatchBlock", + "PSAvoidUsingDeprecatedManifestFields", + "PSAvoidUsingUserNameAndPasswordParams", + "PSAvoidUsingCmdletAliases" output: results.sarif # Upload the SARIF file generated in the previous step From 63b9e8b75dd4e12e54f5ff8612f0664004debffd Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:28:19 -0500 Subject: [PATCH 43/45] test: update workflow --- .github/workflows/powershell.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/powershell.yml b/.github/workflows/powershell.yml index 200e585..26bfe4f 100644 --- a/.github/workflows/powershell.yml +++ b/.github/workflows/powershell.yml @@ -37,11 +37,11 @@ jobs: # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. path: | - .\source\Classes - .\source\helper - .\source\Private - .\source\Public - .\source\tests + source/Classes + source/helper + source/Private + source/Public + source/tests recurse: true # Include your own basic security rules. Removing this option will run all the rules includeRule: | From c842ae9720f9598bb82e9e2c6085a2d1dbdad8fb Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:32:43 -0500 Subject: [PATCH 44/45] test: update workflow --- .github/workflows/powershell.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/powershell.yml b/.github/workflows/powershell.yml index 26bfe4f..200e585 100644 --- a/.github/workflows/powershell.yml +++ b/.github/workflows/powershell.yml @@ -37,11 +37,11 @@ jobs: # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. path: | - source/Classes - source/helper - source/Private - source/Public - source/tests + .\source\Classes + .\source\helper + .\source\Private + .\source\Public + .\source\tests recurse: true # Include your own basic security rules. Removing this option will run all the rules includeRule: | From 0569fd98cc36fd33988411b08f8a9925b4fcdd8c Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:36:41 -0500 Subject: [PATCH 45/45] test: update workflow --- .github/workflows/powershell.yml | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/.github/workflows/powershell.yml b/.github/workflows/powershell.yml index 200e585..0b02f5e 100644 --- a/.github/workflows/powershell.yml +++ b/.github/workflows/powershell.yml @@ -36,25 +36,11 @@ jobs: with: # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. - path: | - .\source\Classes - .\source\helper - .\source\Private - .\source\Public - .\source\tests + path: .\source recurse: true # Include your own basic security rules. Removing this option will run all the rules - includeRule: | - "PSAvoidGlobalAliases", - "PSAvoidUsingConvertToSecureStringWithPlainText", - "PSAvoidUsingPlainTextForPassword", - "PSAvoidUsingInvokeExpression", - "PSUseApprovedVerbs", - "PSAvoidUsingPositionalParameters", - "PSAvoidUsingEmptyCatchBlock", - "PSAvoidUsingDeprecatedManifestFields", - "PSAvoidUsingUserNameAndPasswordParams", - "PSAvoidUsingCmdletAliases" + includeRule: '"PSAvoidGlobalAliases", "PSAvoidUsingConvertToSecureStringWithPlainText", "PSAvoidUsingPlainTextForPassword", "PSAvoidUsingInvokeExpression", "PSUseApprovedVerbs", "PSAvoidUsingPositionalParameters", "PSAvoidUsingEmptyCatchBlock", "PSAvoidUsingDeprecatedManifestFields", "PSAvoidUsingUserNameAndPasswordParams", "PSAvoidUsingCmdletAliases"' + output: results.sarif # Upload the SARIF file generated in the previous step