diff --git a/.gitignore b/.gitignore index 17c483d..d18e461 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ output/ markdownissues.txt node_modules package-lock.json +Aligned.xlsx \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1270b29..3b53a5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,32 @@ The format is based on and uses the types of changes according to [Keep a Change ### Added +- Array list to store the results of the audit. +- Arraylist tests and helper template. +- New testing function. +- Missing properties to CSV. + +### Changed + +- Refactored object initialization to source `RecDescription`, `CISControl`, and `CISDescription` properties from the CSV. +- Added `Automated` and `Connection` properties to the output object. +- All test functions aligned with the test-template. +- Initialize-CISAuditResult refactored to use global test definitions. + +### Fixed + +- Corrected test-template. +- Details added to pass. + +### Docs + +- Updated comments and documentation for new functions. + + +## [0.1.2] - 2024-04-29 + +### Added + - Automated and organized CSV testing and added test 1.1.1. - Functions to merge tests into an Excel benchmark. - Public function for merging tests. @@ -24,6 +50,7 @@ The format is based on and uses the types of changes according to [Keep a Change - Updated comments for new functions. - Updated help documentation. +- Updated online link in public function. ## [0.1.1] - 2024-04-02 diff --git a/README.md b/README.md index 6ec049d..a150f89 100644 Binary files a/README.md and b/README.md differ diff --git a/docs/index.html b/docs/index.html index 70af950..cc5badf 100644 Binary files a/docs/index.html and b/docs/index.html differ diff --git a/helpers/Build-Help.ps1 b/helpers/Build-Help.ps1 index a2d483b..c00d0b8 100644 --- a/helpers/Build-Help.ps1 +++ b/helpers/Build-Help.ps1 @@ -4,7 +4,7 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1 <# - $ver = "v0.1.1" + $ver = "v0.1.2" git checkout main git pull origin main git tag -a $ver -m "Release version $ver Bugfix Update" diff --git a/helpers/CIS 365 v3.0.0 Controls/Test-Template.ps1 b/helpers/CIS 365 v3.0.0 Controls/Test-Template.ps1 new file mode 100644 index 0000000..5f49dca --- /dev/null +++ b/helpers/CIS 365 v3.0.0 Controls/Test-Template.ps1 @@ -0,0 +1,97 @@ +function Test-Template { + [CmdletBinding()] + param ( + # Parameters can be added if needed + ) + + begin { + # Initialization code, if needed + # Load necessary scripts, define variables, etc. + } + + process { + # Fetch relevant data + # Example: $data = Get-SomeData + + # Process the data to evaluate compliance + # Example: $compliantItems = $data | Where-Object { $_.Property -eq 'ExpectedValue' } + # Example: $nonCompliantItems = $data | Where-Object { $_.Property -ne 'ExpectedValue' } + + # Prepare failure reasons for non-compliant items + $failureReasons = $nonCompliantItems | ForEach-Object { + # Example: "Item: $($_.Name) - Reason: Missing expected value" + } + $failureReasons = $failureReasons -join "`n" + + # Prepare details for non-compliant items + $nonCompliantDetails = $nonCompliantItems | ForEach-Object { + # Example: "$($_.Name) - Value: $($_.Property)" + } + $nonCompliantDetails = $nonCompliantDetails -join "`n" + + # 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 = [CISAuditResult]::new() + $auditResult.Status = if ($nonCompliantItems) { 'Fail' } else { 'Pass' } + $auditResult.ELevel = 'E3' # Modify as needed + $auditResult.ProfileLevel = 'L1' # Modify as needed + $auditResult.Rec = '1.1.1' # Modify as needed + $auditResult.RecDescription = "Description of the recommendation" # Modify as needed + $auditResult.CISControlVer = 'v8' # Modify as needed + $auditResult.CISControl = "5.4" # Modify as needed + $auditResult.CISDescription = "Description of the CIS control" # Modify as needed + $auditResult.IG1 = $true # Modify as needed + $auditResult.IG2 = $true # Modify as needed + $auditResult.IG3 = $true # Modify as needed + $auditResult.Result = $nonCompliantItems.Count -eq 0 + $auditResult.Details = $details + $auditResult.FailureReason = if ($nonCompliantItems) { + "Non-compliant items:`n$failureReasons" + } else { + "N/A" + } + + # Example output object for a pass result + # Status : Pass + # ELevel : E3 + # ProfileLevel : L2 + # Rec : 8.1.1 + # RecDescription : Ensure external file sharing in Teams is enabled for only approved cloud storage services + # CISControlVer : v8 + # CISControl : 3.3 + # CISDescription : Configure Data Access Control Lists + # IG1 : True + # IG2 : True + # IG3 : True + # Result : True + # Details : Compliant Items: 5 + # FailureReason : N/A + + # Example output object for a fail result + # Status : Fail + # ELevel : E3 + # ProfileLevel : L2 + # Rec : 8.1.1 + # RecDescription : Ensure external file sharing in Teams is enabled for only approved cloud storage services + # CISControlVer : v8 + # CISControl : 3.3 + # CISDescription : Configure Data Access Control Lists + # IG1 : True + # IG2 : True + # IG3 : True + # Result : False + # Details : Non-Compliant Items: 2 + # FailureReason : Non-compliant items:`nUsername | Roles | HybridStatus | Missing Licence + } + + end { + # Return the audit result + return $auditResult + } +} diff --git a/source/Classes/CISAuditResult.ps1 b/source/Classes/CISAuditResult.ps1 index 8d04777..2cc80fd 100644 --- a/source/Classes/CISAuditResult.ps1 +++ b/source/Classes/CISAuditResult.ps1 @@ -2,6 +2,8 @@ class CISAuditResult { [string]$Status [string]$ELevel [string]$ProfileLevel + [bool]$Automated + [string]$Connection [string]$Rec [string]$RecDescription [string]$CISControlVer = 'v8' diff --git a/source/Private/Initialize-CISAuditResult.ps1 b/source/Private/Initialize-CISAuditResult.ps1 new file mode 100644 index 0000000..b1e2e09 --- /dev/null +++ b/source/Private/Initialize-CISAuditResult.ps1 @@ -0,0 +1,45 @@ +function Initialize-CISAuditResult { + param ( + [Parameter(Mandatory = $true)] + [string]$Rec, + + [Parameter(Mandatory = $true)] + [bool]$Result, + + [Parameter(Mandatory = $true)] + [string]$Status, + + [Parameter(Mandatory = $true)] + [string]$Details, + + [Parameter(Mandatory = $true)] + [string]$FailureReason + ) + + # Import the test definitions CSV file + $testDefinitions = $script:TestDefinitionsObject + + # Find the row that matches the provided recommendation (Rec) + $testDefinition = $testDefinitions | Where-Object { $_.Rec -eq $Rec } + + # Create an instance of CISAuditResult and populate it + $auditResult = [CISAuditResult]::new() + $auditResult.Rec = $Rec + $auditResult.ELevel = $testDefinition.ELevel + $auditResult.ProfileLevel = $testDefinition.ProfileLevel + $auditResult.IG1 = [bool]::Parse($testDefinition.IG1) + $auditResult.IG2 = [bool]::Parse($testDefinition.IG2) + $auditResult.IG3 = [bool]::Parse($testDefinition.IG3) + $auditResult.RecDescription = $testDefinition.RecDescription + $auditResult.CISControl = $testDefinition.CISControl + $auditResult.CISDescription = $testDefinition.CISDescription + $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 + + return $auditResult +} diff --git a/source/Public/Get-AdminRoleUserLicense.ps1 b/source/Public/Get-AdminRoleUserLicense.ps1 index 6c307ee..fa2a49a 100644 --- a/source/Public/Get-AdminRoleUserLicense.ps1 +++ b/source/Public/Get-AdminRoleUserLicense.ps1 @@ -36,8 +36,8 @@ function Get-AdminRoleUserLicense { Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome } - $adminRoleUsers = @() - $userIds = @() + $adminRoleUsers = [System.Collections.ArrayList]::new() + $userIds = [System.Collections.ArrayList]::new() } Process { @@ -50,24 +50,28 @@ function Get-AdminRoleUserLicense { $userDetails = Get-MgUser -UserId $user.PrincipalId -Property "DisplayName, UserPrincipalName, Id, onPremisesSyncEnabled" -ErrorAction SilentlyContinue if ($userDetails) { - $userIds += $user.PrincipalId - $adminRoleUsers += [PSCustomObject]@{ - RoleName = $role.DisplayName - UserName = $userDetails.DisplayName - UserPrincipalName = $userDetails.UserPrincipalName - UserId = $userDetails.Id - HybridUser = $userDetails.onPremisesSyncEnabled - Licenses = $null # Initialize as $null - } + [void]($userIds.Add($user.PrincipalId)) + [void]( + $adminRoleUsers.Add( + [PSCustomObject]@{ + RoleName = $role.DisplayName + UserName = $userDetails.DisplayName + UserPrincipalName = $userDetails.UserPrincipalName + UserId = $userDetails.Id + HybridUser = $userDetails.onPremisesSyncEnabled + Licenses = $null # Initialize as $null + } + ) + ) } } } - foreach ($userId in $userIds | Select-Object -Unique) { + foreach ($userId in $userIds.ToArray() | Select-Object -Unique) { $licenses = Get-MgUserLicenseDetail -UserId $userId -ErrorAction SilentlyContinue if ($licenses) { $licenseList = ($licenses.SkuPartNumber -join '|') - $adminRoleUsers | Where-Object { $_.UserId -eq $userId } | ForEach-Object { + $adminRoleUsers.ToArray() | Where-Object { $_.UserId -eq $userId } | ForEach-Object { $_.Licenses = $licenseList } } diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index cff7e59..fb0ee29 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -57,7 +57,7 @@ - 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 - Online Version: https://github.com/CriticalSolutionsNetwork/M365FoundationsCISReport + https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit #> function Invoke-M365SecurityAudit { @@ -161,7 +161,8 @@ function Invoke-M365SecurityAudit { # 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 switch ($PSCmdlet.ParameterSetName) { 'ELevelFilter' { @@ -209,7 +210,7 @@ function Invoke-M365SecurityAudit { } # End Begin Process { - $allAuditResults = @() # 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" @@ -242,7 +243,7 @@ function Invoke-M365SecurityAudit { Write-Host "Running $functionName..." $result = & $functionName @paramList # Assuming each function returns an array of CISAuditResult or a single CISAuditResult - $allAuditResults += $result + [void]($allAuditResults.add($Result)) } } } @@ -253,7 +254,7 @@ function Invoke-M365SecurityAudit { Disconnect-M365Suite } # Return all collected audit results - return $allAuditResults + return $allAuditResults.ToArray() # Check if the Disconnect switch is present } } \ No newline at end of file diff --git a/source/helper/TestDefinitions.csv b/source/helper/TestDefinitions.csv index 5bef5ae..32c46b7 100644 --- a/source/helper/TestDefinitions.csv +++ b/source/helper/TestDefinitions.csv @@ -1,52 +1,52 @@ -Index,TestFileName,Rec,ELevel,ProfileLevel,IG1,IG2,IG3,Automated -1,Test-AdministrativeAccountCompliance.ps1,1.1.1,E3,L1,TRUE,TRUE,TRUE,FALSE -2,Test-GlobalAdminsCount.ps1,1.1.3,E3,L1,TRUE,TRUE,TRUE,TRUE -3,Test-ManagedApprovedPublicGroups.ps1,1.2.1,E3,L2,TRUE,TRUE,TRUE,TRUE -4,Test-BlockSharedMailboxSignIn.ps1,1.2.2,E3,L1,FALSE,FALSE,FALSE,TRUE -5,Test-PasswordNeverExpirePolicy.ps1,1.3.1,E3,L1,TRUE,TRUE,TRUE,TRUE -6,Test-ExternalSharingCalendars.ps1,1.3.3,E3,L2,FALSE,TRUE,TRUE,TRUE -7,Test-CustomerLockbox.ps1,1.3.6,E5,L2,FALSE,FALSE,FALSE,TRUE -8,Test-SafeLinksOfficeApps.ps1,2.1.1,E5,L2,TRUE,TRUE,TRUE,TRUE -9,Test-CommonAttachmentFilter.ps1,2.1.2,E3,L1,FALSE,TRUE,TRUE,TRUE -10,Test-NotifyMalwareInternal.ps1,2.1.3,E3,L1,FALSE,TRUE,TRUE,TRUE -11,Test-SafeAttachmentsPolicy.ps1,2.1.4,E5,L2,FALSE,FALSE,TRUE,TRUE -12,Test-SafeAttachmentsTeams.ps1,2.1.5,E5,L2,TRUE,TRUE,TRUE,TRUE -13,Test-SpamPolicyAdminNotify.ps1,2.1.6,E3,L1,FALSE,TRUE,TRUE,TRUE -14,Test-AntiPhishingPolicy.ps1,2.1.7,E5,L1,FALSE,FALSE,TRUE,TRUE -15,Test-EnableDKIM.ps1,2.1.9,E3,L1,FALSE,TRUE,TRUE,TRUE -16,Test-AuditLogSearch.ps1,3.1.1,E3,L1,TRUE,TRUE,TRUE,TRUE -17,Test-RestrictTenantCreation.ps1,5.1.2.3,E3,L1,FALSE,FALSE,FALSE,TRUE -18,Test-PasswordHashSync.ps1,5.1.8.1,E3,L1,FALSE,TRUE,TRUE,TRUE -19,Test-AuditDisabledFalse.ps1,6.1.1,E3,L1,TRUE,TRUE,TRUE,TRUE -20,Test-MailboxAuditingE3.ps1,6.1.2,E3,L1,TRUE,TRUE,TRUE,TRUE -21,Test-MailboxAuditingE5.ps1,6.1.3,E5,L1,TRUE,TRUE,TRUE,TRUE -22,Test-BlockMailForwarding.ps1,6.2.1,E3,L1,FALSE,FALSE,FALSE,TRUE -23,Test-NoWhitelistDomains.ps1,6.2.2,E3,L1,FALSE,FALSE,FALSE,TRUE -24,Test-IdentifyExternalEmail.ps1,6.2.3,E3,L1,FALSE,FALSE,FALSE,TRUE -25,Test-RestrictOutlookAddins.ps1,6.3.1,E3,L2,FALSE,TRUE,TRUE,TRUE -26,Test-ModernAuthExchangeOnline.ps1,6.5.1,E3,L1,FALSE,TRUE,TRUE,TRUE -27,Test-MailTipsEnabled.ps1,6.5.2,E3,L2,FALSE,FALSE,FALSE,TRUE -28,Test-RestrictStorageProvidersOutlook.ps1,6.5.3,E3,L2,TRUE,TRUE,TRUE,TRUE -29,Test-ModernAuthSharePoint.ps1,7.2.1,E3,L1,FALSE,TRUE,TRUE,TRUE -30,Test-SharePointAADB2B.ps1,7.2.2,E3,L1,FALSE,FALSE,FALSE,TRUE -31,Test-RestrictExternalSharing.ps1,7.2.3,E3,L1,TRUE,TRUE,TRUE,TRUE -32,Test-OneDriveContentRestrictions.ps1,7.2.4,E3,L2,TRUE,TRUE,TRUE,TRUE -33,Test-SharePointGuestsItemSharing.ps1,7.2.5,E3,L2,TRUE,TRUE,TRUE,TRUE -34,Test-SharePointExternalSharingDomains.ps1,7.2.6,E3,L2,TRUE,TRUE,TRUE,TRUE -35,Test-LinkSharingRestrictions.ps1,7.2.7,E3,L1,TRUE,TRUE,TRUE,TRUE -36,Test-GuestAccessExpiration.ps1,7.2.9,E3,L1,FALSE,FALSE,FALSE,TRUE -37,Test-ReauthWithCode.ps1,7.2.10,E3,L1,FALSE,FALSE,FALSE,TRUE -38,Test-DisallowInfectedFilesDownload.ps1,7.3.1,E5,L2,TRUE,TRUE,TRUE,TRUE -39,Test-OneDriveSyncRestrictions.ps1,7.3.2,E3,L2,FALSE,FALSE,FALSE,TRUE -40,Test-RestrictCustomScripts.ps1,7.3.4,E3,L1,FALSE,FALSE,TRUE,TRUE -41,Test-TeamsExternalFileSharing.ps1,8.1.1,E3,L2,TRUE,TRUE,TRUE,TRUE -42,Test-BlockChannelEmails.ps1,8.1.2,E3,L1,FALSE,FALSE,FALSE,TRUE -43,Test-TeamsExternalAccess.ps1,8.2.1,E3,L2,FALSE,FALSE,FALSE,TRUE -44,Test-NoAnonymousMeetingJoin.ps1,8.5.1,E3,L2,FALSE,FALSE,FALSE,TRUE -45,Test-NoAnonymousMeetingStart.ps1,8.5.2,E3,L1,FALSE,FALSE,FALSE,TRUE -46,Test-OrgOnlyBypassLobby.ps1,8.5.3,E3,L1,FALSE,FALSE,TRUE,TRUE -47,Test-DialInBypassLobby.ps1,8.5.4,E3,L1,FALSE,FALSE,FALSE,TRUE -48,Test-MeetingChatNoAnonymous.ps1,8.5.5,E3,L1,FALSE,FALSE,FALSE,TRUE -49,Test-OrganizersPresent.ps1,8.5.6,E3,L1,FALSE,FALSE,FALSE,TRUE -50,Test-ExternalNoControl.ps1,8.5.7,E3,L1,FALSE,FALSE,FALSE,TRUE -51,Test-ReportSecurityInTeams.ps1,8.6.1,E3,L1,FALSE,FALSE,FALSE,TRUE +Index,TestFileName,Rec,RecDescription,ELevel,ProfileLevel,CISControl,CISDescription,IG1,IG2,IG3,Automated,Connection +1,Test-AdministrativeAccountCompliance.ps1,1.1.1,Ensure Administrative accounts are separate and cloud-only,E3,L1,5.4,Restrict Administrator Privileges to Dedicated Administrator Accounts,TRUE,TRUE,TRUE,FALSE,AzureAD +2,Test-GlobalAdminsCount.ps1,1.1.3,Ensure that between two and four global admins are designated,E3,L1,5.1,Establish and Maintain an Inventory of Accounts,TRUE,TRUE,TRUE,TRUE,Microsoft Graph +3,Test-ManagedApprovedPublicGroups.ps1,1.2.1,Ensure that only organizationally managed/approved public groups exist,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,Microsoft Graph +4,Test-BlockSharedMailboxSignIn.ps1,1.2.2,Ensure sign-in to shared mailboxes is blocked,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,AzureAD | EXO +5,Test-PasswordNeverExpirePolicy.ps1,1.3.1,Ensure the 'Password expiration policy' is set to 'Set passwords to never expire',E3,L1,5.2,Use Unique Passwords,TRUE,TRUE,TRUE,TRUE,Microsoft Graph +6,Test-ExternalSharingCalendars.ps1,1.3.3,Ensure 'External sharing' of calendars is not available,E3,L2,4.8,Uninstall or Disable Unnecessary Services on Enterprise Assets and Software,FALSE,TRUE,TRUE,TRUE,EXO +7,Test-CustomerLockbox.ps1,1.3.6,Ensure the customer lockbox feature is enabled,E5,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO +8,Test-SafeLinksOfficeApps.ps1,2.1.1,Ensure Safe Links for Office Applications is Enabled,E5,L2,10.1,Deploy and Maintain Anti-Malware Software,TRUE,TRUE,TRUE,TRUE,EXO +9,Test-CommonAttachmentFilter.ps1,2.1.2,Ensure the Common Attachment Types Filter is enabled,E3,L1,9.6,Block Unnecessary File Types,FALSE,TRUE,TRUE,TRUE,EXO +10,Test-NotifyMalwareInternal.ps1,2.1.3,Ensure notifications for internal users sending malware is Enabled,E3,L1,17.5,Assign Key Roles and Responsibilities,FALSE,TRUE,TRUE,TRUE,EXO +11,Test-SafeAttachmentsPolicy.ps1,2.1.4,Ensure Safe Attachments policy is enabled,E5,L2,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO +12,Test-SafeAttachmentsTeams.ps1,2.1.5,"Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled",E5,L2,"9.7, 10.1","Deploy and Maintain Email Server Anti-Malware Protections, Deploy and Maintain Anti-Malware Software",TRUE,TRUE,TRUE,TRUE,EXO +13,Test-SpamPolicyAdminNotify.ps1,2.1.6,Ensure Exchange Online Spam Policies are set to notify administrators,E3,L1,17.5,Assign Key Roles and Responsibilities,FALSE,TRUE,TRUE,TRUE,EXO +14,Test-AntiPhishingPolicy.ps1,2.1.7,Ensure that an anti-phishing policy has been created,E5,L1,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO +15,Test-EnableDKIM.ps1,2.1.9,Ensure that DKIM is enabled for all Exchange Online Domains,E3,L1,9.5,Implement DMARC,FALSE,TRUE,TRUE,TRUE,EXO +16,Test-AuditLogSearch.ps1,3.1.1,Ensure Microsoft 365 audit log search is Enabled,E3,L1,8.2,Collect Audit Logs,TRUE,TRUE,TRUE,TRUE,EXO +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,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,EXO +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 +25,Test-RestrictOutlookAddins.ps1,6.3.1,Ensure users installing Outlook add-ins is not allowed,E3,L2,9.4,Restrict Unnecessary or Unauthorized Browser and Email Client Extensions,FALSE,TRUE,TRUE,TRUE,EXO +26,Test-ModernAuthExchangeOnline.ps1,6.5.1,Ensure modern authentication for Exchange Online is enabled (Automated),E3,L1,3.1,Encrypt Sensitive Data in Transit,FALSE,TRUE,TRUE,TRUE,EXO +27,Test-MailTipsEnabled.ps1,6.5.2,Ensure MailTips are enabled for end users,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO +28,Test-RestrictStorageProvidersOutlook.ps1,6.5.3,Ensure additional storage providers are restricted in Outlook on the web,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,EXO +29,Test-ModernAuthSharePoint.ps1,7.2.1,Modern Authentication for SharePoint Applications,E3,L1,3.1,Encrypt Sensitive Data in Transit,FALSE,TRUE,TRUE,TRUE,SPO +30,Test-SharePointAADB2B.ps1,7.2.2,Ensure reauthentication with verification code is restricted,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,SPO +31,Test-RestrictExternalSharing.ps1,7.2.3,Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled,E3,L1,0,Explicitly Not Mapped,TRUE,TRUE,TRUE,TRUE,SPO +32,Test-OneDriveContentRestrictions.ps1,7.2.4,Ensure external content sharing is restricted,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO +33,Test-SharePointGuestsItemSharing.ps1,7.2.5,Ensure OneDrive content sharing is restricted,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO +34,Test-SharePointExternalSharingDomains.ps1,7.2.6,Ensure that SharePoint guest users cannot share items they don't own,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO +35,Test-LinkSharingRestrictions.ps1,7.2.7,Ensure SharePoint external sharing is managed through domain whitelist/blacklists,E3,L1,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO +36,Test-GuestAccessExpiration.ps1,7.2.9,Ensure link sharing is restricted in SharePoint and OneDrive,E3,L1,3.3,Configure Data Access Control Lists,FALSE,FALSE,FALSE,TRUE,SPO +37,Test-ReauthWithCode.ps1,7.2.10,Ensure guest access to a site or OneDrive will expire automatically,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,SPO +38,Test-DisallowInfectedFilesDownload.ps1,7.3.1,Ensure Office 365 SharePoint infected files are disallowed for download,E5,L2,10.1,Deploy and Maintain Anti-Malware Software,TRUE,TRUE,TRUE,TRUE,SPO +39,Test-OneDriveSyncRestrictions.ps1,7.3.2,Ensure OneDrive sync is restricted for unmanaged devices,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,SPO +40,Test-RestrictCustomScripts.ps1,7.3.4,Ensure custom script execution is restricted on site collections,E3,L1,2.7,Allowlist Authorized Scripts,FALSE,FALSE,TRUE,TRUE,SPO +41,Test-TeamsExternalFileSharing.ps1,8.1.1,Ensure external file sharing in Teams is enabled for only approved cloud storage services,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,Microsoft Teams +42,Test-BlockChannelEmails.ps1,8.1.2,Ensure users can't send emails to a channel email address,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +43,Test-TeamsExternalAccess.ps1,8.2.1,Ensure 'external access' is restricted in the Teams admin center,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +44,Test-NoAnonymousMeetingJoin.ps1,8.5.1,Ensure anonymous users can't join a meeting,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +45,Test-NoAnonymousMeetingStart.ps1,8.5.2,Ensure anonymous users and dial-in callers can't start a meeting,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +46,Test-OrgOnlyBypassLobby.ps1,8.5.3,Ensure only people in my org can bypass the lobby,E3,L1,6.8,Define and Maintain Role-Based Access Control,FALSE,FALSE,TRUE,TRUE,Microsoft Teams +47,Test-DialInBypassLobby.ps1,8.5.4,Ensure users dialing in can't bypass the lobby,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +48,Test-MeetingChatNoAnonymous.ps1,8.5.5,Ensure meeting chat does not allow anonymous users,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +49,Test-OrganizersPresent.ps1,8.5.6,Ensure only organizers and co-organizers can present,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +50,Test-ExternalNoControl.ps1,8.5.7,Ensure external participants can't give or request control,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams +51,Test-ReportSecurityInTeams.ps1,8.6.1,Ensure users can report security concerns in Teams,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams | EXO diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 3273774..21ab959 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -1,12 +1,15 @@ function Test-AdministrativeAccountCompliance { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) + begin { - #. C:\Temp\CISAuditResult.ps1 + #. .\source\Classes\CISAuditResult.ps1 $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') } + process { $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } $adminRoleUsers = @() @@ -50,22 +53,27 @@ function Test-AdministrativeAccountCompliance { "$($_.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)" + } - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($nonCompliantUsers) { 'Fail' } else { 'Pass' } - $auditResult.ELevel = 'E3' - $auditResult.ProfileLevel = 'L1' - $auditResult.Rec = '1.1.1' - $auditResult.RecDescription = "Ensure Administrative accounts are separate and cloud-only" - $auditResult.CISControlVer = 'v8' - $auditResult.CISControl = "5.4" - $auditResult.CISDescription = "Restrict Administrator Privileges to Dedicated Administrator Accounts" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $nonCompliantUsers.Count -eq 0 - $auditResult.Details = "Compliant Accounts: $($uniqueAdminRoleUsers.Count - $nonCompliantUsers.Count); Non-Compliant Accounts: $($nonCompliantUsers.Count)" - $auditResult.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 + } + + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-AntiPhishingPolicy.ps1 b/source/tests/Test-AntiPhishingPolicy.ps1 index de8f0ed..88b103e 100644 --- a/source/tests/Test-AntiPhishingPolicy.ps1 +++ b/source/tests/Test-AntiPhishingPolicy.ps1 @@ -1,17 +1,19 @@ function Test-AntiPhishingPolicy { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed + #$auditResults = @() } process { - # 2.1.7 Ensure that an anti-phishing policy has been created + # 2.1.7 Ensure that an anti-phishing policy has been created # Retrieve and validate the anti-phishing policies $antiPhishPolicies = Get-AntiPhishPolicy @@ -24,37 +26,54 @@ function Test-AntiPhishingPolicy { } # Check if there is at least one policy that meets the requirements - $isCompliant = $validatedPolicies.Count -gt 0 + $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 failure details if policies are not compliant - $failureDetails = if (-not $isCompliant) { - "No anti-phishing policy is fully compliant with CIS benchmark requirements." - } else { - "Compliant Anti-Phish Policy Names: " + ($validatedPolicies.Name -join ', ') + # 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" } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($isCompliant) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E5" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "2.1.7" - $auditResult.RecDescription = "Ensure that an anti-phishing policy has been created" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "9.7" - $auditResult.CISDescription = "Deploy and Maintain Email Server Anti-Malware Protections" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $true - $auditResult.Result = $isCompliant - $auditResult.Details = $failureDetails - $auditResult.FailureReason = if (-not $isCompliant) { "Anti-phishing policies do not meet CIS benchmark requirements." } else { "N/A" } + # Prepare details for non-compliant items + $nonCompliantDetails = $nonCompliantItems | ForEach-Object { + "Policy: $($_.Name)" + } + $nonCompliantDetails = $nonCompliantDetails -join "`n" - $auditResults += $auditResult + # Prepare details based on compliance + $details = if ($nonCompliantItems) { + "Non-Compliant Items: $($nonCompliantItems.Count)`nDetails:`n$nonCompliantDetails" + } + else { + "Compliant Items: $($compliantItems.Count)" + } + + # 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 + } + + # Create and populate the CISAuditResult object + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return auditResult + return $auditResult } } diff --git a/source/tests/Test-AuditDisabledFalse.ps1 b/source/tests/Test-AuditDisabledFalse.ps1 index fe56b46..3f91a83 100644 --- a/source/tests/Test-AuditDisabledFalse.ps1 +++ b/source/tests/Test-AuditDisabledFalse.ps1 @@ -1,43 +1,51 @@ function Test-AuditDisabledFalse { [CmdletBinding()] + # Aligned param ( # Parameters can be added if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 6.1.1 (L1) Ensure 'AuditDisabled' organizationally is set to 'False' - # Pass if AuditDisabled is False. Fail otherwise. + + # Retrieve the AuditDisabled configuration $auditDisabledConfig = Get-OrganizationConfig | Select-Object AuditDisabled $auditNotDisabled = -not $auditDisabledConfig.AuditDisabled - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($auditNotDisabled) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "6.1.1" - $auditResult.RecDescription = "Ensure 'AuditDisabled' organizationally is set to 'False'" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "8.2" - $auditResult.CISDescription = "Collect Audit Logs" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $auditNotDisabled - $auditResult.Details = if ($auditNotDisabled) { "Audit is not disabled organizationally" } else { "Audit is disabled organizationally" } - $auditResult.FailureReason = if (-not $auditNotDisabled) { "AuditDisabled is set to True" } else { "N/A" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $auditNotDisabled) { + "AuditDisabled is set to True" + } + else { + "N/A" + } - $auditResults += $auditResult + $details = if ($auditNotDisabled) { + "Audit is not disabled organizationally" + } + else { + "Audit is disabled organizationally" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "6.1.1" + Result = $auditNotDisabled + Status = if ($auditNotDisabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-AuditLogSearch.ps1 b/source/tests/Test-AuditLogSearch.ps1 index 3249872..023f569 100644 --- a/source/tests/Test-AuditLogSearch.ps1 +++ b/source/tests/Test-AuditLogSearch.ps1 @@ -1,43 +1,52 @@ function Test-AuditLogSearch { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 3.1.1 (L1) Ensure Microsoft 365 audit log search is Enabled - # Pass if UnifiedAuditLogIngestionEnabled is True. Fail otherwise. + + # Retrieve the audit log configuration $auditLogConfig = Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled $auditLogResult = $auditLogConfig.UnifiedAuditLogIngestionEnabled - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($auditLogResult) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "3.1.1" - $auditResult.RecDescription = "Ensure Microsoft 365 audit log search is Enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "8.2" - $auditResult.CISDescription = "Collect Audit Logs" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $auditLogResult - $auditResult.Details = "UnifiedAuditLogIngestionEnabled: $($auditLogConfig.UnifiedAuditLogIngestionEnabled)" - $auditResult.FailureReason = if (-not $auditLogResult) { "Audit log search is not enabled" } else { "N/A" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $auditLogResult) { + "Audit log search is not enabled" + } + else { + "N/A" + } + + $details = if ($auditLogResult) { + "UnifiedAuditLogIngestionEnabled: True" + } + else { + "UnifiedAuditLogIngestionEnabled: False" + } + + # 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 - $auditResults += $auditResult } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-BlockChannelEmails.ps1 b/source/tests/Test-BlockChannelEmails.ps1 index fc438ee..c8ed086 100644 --- a/source/tests/Test-BlockChannelEmails.ps1 +++ b/source/tests/Test-BlockChannelEmails.ps1 @@ -1,44 +1,51 @@ function Test-BlockChannelEmails { [CmdletBinding()] param ( + # Aligned # Parameters can be added here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 8.1.2 (L1) Ensure users can't send emails to a channel email address - # Connect to Teams PowerShell using Connect-MicrosoftTeams + # Retrieve Teams client configuration $teamsClientConfig = Get-CsTeamsClientConfiguration -Identity Global $allowEmailIntoChannel = $teamsClientConfig.AllowEmailIntoChannel - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # This control is Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.1.2" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the benchmark - $auditResult.IG2 = $false # Set based on the benchmark - $auditResult.IG3 = $false # Set based on the benchmark - $auditResult.RecDescription = "Ensure users can't send emails to a channel email address" - $auditResult.Result = -not $allowEmailIntoChannel - $auditResult.Details = "AllowEmailIntoChannel is set to $allowEmailIntoChannel" - $auditResult.FailureReason = if ($allowEmailIntoChannel) { "Emails can be sent to a channel email address" } else { "N/A" } - $auditResult.Status = if (-not $allowEmailIntoChannel) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($allowEmailIntoChannel) { + "Emails can be sent to a channel email address" + } + else { + "N/A" + } - $auditResults += $auditResult + $details = if ($allowEmailIntoChannel) { + "AllowEmailIntoChannel is set to True" + } + else { + "AllowEmailIntoChannel is set to False" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "8.1.2" + Result = -not $allowEmailIntoChannel + Status = if (-not $allowEmailIntoChannel) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-BlockMailForwarding.ps1 b/source/tests/Test-BlockMailForwarding.ps1 index d4bcaea..8039d06 100644 --- a/source/tests/Test-BlockMailForwarding.ps1 +++ b/source/tests/Test-BlockMailForwarding.ps1 @@ -1,51 +1,52 @@ function Test-BlockMailForwarding { [CmdletBinding()] param ( + # Aligned Compare # Parameters can be added if needed ) begin { - - $auditResult = [CISAuditResult]::new() - $auditResult.Rec = "6.2.1" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.RecDescription = "Ensure all forms of mail forwarding are blocked and/or disabled" + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { - # Verify that no rules are forwarding the email to external domains - $transportRules = Get-TransportRule | Where-Object { $_.RedirectMessageTo -ne $null } + # 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 - $auditResult.Result = $forwardingBlocked - $auditResult.Details = if ($transportRules.Count -gt 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" + } + + $details = if ($transportRules.Count -gt 0) { $transportRules | ForEach-Object { "$($_.Name) redirects to $($_.RedirectMessageTo)" } -join " | " - } else { + } + else { "Step 1: No forwarding rules found. Please proceed with Step 2 described in CIS Benchmark." } - $auditResult.FailureReason = if (-not $forwardingBlocked) { - "Mail forwarding rules found: $($transportRules.Name -join ', ')" - } else { - "N/A" + + $params = @{ + Rec = "6.2.1" + Result = $forwardingBlocked + Status = if ($forwardingBlocked) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons } - $auditResult.Status = if ($forwardingBlocked) { "Pass" } else { "Fail" } + $auditResult = Initialize-CISAuditResult @params } end { - # Return the result object + # Return the audit result return $auditResult } } - - - - diff --git a/source/tests/Test-BlockSharedMailboxSignIn.ps1 b/source/tests/Test-BlockSharedMailboxSignIn.ps1 index b74afad..7f4711b 100644 --- a/source/tests/Test-BlockSharedMailboxSignIn.ps1 +++ b/source/tests/Test-BlockSharedMailboxSignIn.ps1 @@ -1,48 +1,53 @@ function Test-BlockSharedMailboxSignIn { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 1.2.2 (L1) Ensure sign-in to shared mailboxes is blocked - # Pass if all shared mailboxes have AccountEnabled set to False. - # Fail if any shared mailbox has AccountEnabled set to True. - # Review: Details property - Add verbosity. + # 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 - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # Control is explicitly not mapped - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "1.2.2" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Control is not mapped, hence IG1 is false - $auditResult.IG2 = $false # Control is not mapped, hence IG2 is false - $auditResult.IG3 = $false # Control is not mapped, hence IG3 is false - $auditResult.RecDescription = "Ensure sign-in to shared mailboxes is blocked" - $auditResult.Result = $allBlocked - $auditResult.Details = "Enabled Mailboxes: $($enabledMailboxes -join ', ')" - $auditResult.FailureReason = if ($allBlocked) { "N/A" } else { "Some mailboxes have sign-in enabled: $($enabledMailboxes -join ', ')" } - $auditResult.Status = if ($allBlocked) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $allBlocked) { + "Some mailboxes have sign-in enabled: $($enabledMailboxes -join ', ')" + } + else { + "N/A" + } - $auditResults += $auditResult + $details = if ($allBlocked) { + "All shared mailboxes have sign-in blocked." + } + else { + "Enabled Mailboxes: $($enabledMailboxes -join ', ')" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "1.2.2" + Result = $allBlocked + Status = if ($allBlocked) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-CommonAttachmentFilter.ps1 b/source/tests/Test-CommonAttachmentFilter.ps1 index 7f4ff33..9b60797 100644 --- a/source/tests/Test-CommonAttachmentFilter.ps1 +++ b/source/tests/Test-CommonAttachmentFilter.ps1 @@ -1,46 +1,51 @@ function Test-CommonAttachmentFilter { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 2.1.2 (L1) Ensure the Common Attachment Types Filter is enabled - # Pass if EnableFileFilter is set to True. Fail otherwise. + # Retrieve the attachment filter policy $attachmentFilter = Get-MalwareFilterPolicy -Identity Default | Select-Object EnableFileFilter $result = $attachmentFilter.EnableFileFilter - $details = "File Filter Enabled: $($attachmentFilter.EnableFileFilter)" - $failureReason = if ($result) { "N/A" } else { "Common Attachment Types Filter is disabled" } - $status = if ($result) { "Pass" } else { "Fail" } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = $status - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "2.1.2" - $auditResult.RecDescription = "Ensure the Common Attachment Types Filter is enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "9.6" - $auditResult.CISDescription = "Block Unnecessary File Types" - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $result - $auditResult.Details = $details - $auditResult.FailureReason = $failureReason + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $result) { + "Common Attachment Types Filter is disabled" + } + else { + "N/A" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-CustomerLockbox.ps1 b/source/tests/Test-CustomerLockbox.ps1 index 542ce5c..c0723f9 100644 --- a/source/tests/Test-CustomerLockbox.ps1 +++ b/source/tests/Test-CustomerLockbox.ps1 @@ -1,40 +1,51 @@ function Test-CustomerLockbox { [CmdletBinding()] param ( - # Define your parameters here + # Aligned + # Define your parameters here if needed ) begin { - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 1.3.6 (L2) Ensure the customer lockbox feature is enabled + + # Retrieve the organization configuration $orgConfig = Get-OrganizationConfig | Select-Object CustomerLockBoxEnabled $customerLockboxEnabled = $orgConfig.CustomerLockBoxEnabled - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($customerLockboxEnabled) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E5" - $auditResult.ProfileLevel = "L2" - $auditResult.Rec = "1.3.6" - $auditResult.RecDescription = "Ensure the customer lockbox feature is enabled" - $auditResult.CISControlVer = 'v8' - $auditResult.CISControl = "0.0" # As per the snapshot provided, this is explicitly not mapped - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.Result = $customerLockboxEnabled - $auditResult.Details = "Customer Lockbox Enabled: $customerLockboxEnabled" - $auditResult.FailureReason = if ($customerLockboxEnabled) { "N/A" } else { "Customer lockbox feature is not enabled." } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $customerLockboxEnabled) { + "Customer lockbox feature is not enabled." + } + else { + "N/A" + } - $auditResults += $auditResult + $details = if ($customerLockboxEnabled) { + "Customer Lockbox Enabled: True" + } + else { + "Customer Lockbox Enabled: False" + } + + # Create and populate the CISAuditResult object # + $params = @{ + Rec = "1.3.6" + Result = $customerLockboxEnabled + Status = if ($customerLockboxEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-DialInBypassLobby.ps1 b/source/tests/Test-DialInBypassLobby.ps1 index 122a30a..dd2a47b 100644 --- a/source/tests/Test-DialInBypassLobby.ps1 +++ b/source/tests/Test-DialInBypassLobby.ps1 @@ -1,45 +1,51 @@ function Test-DialInBypassLobby { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 8.5.4 (L1) Ensure users dialing in can't bypass the lobby - # Connect to Teams PowerShell using Connect-MicrosoftTeams - + # Retrieve Teams meeting policy for PSTN users $CsTeamsMeetingPolicyPSTN = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowPSTNUsersToBypassLobby $PSTNBypassDisabled = -not $CsTeamsMeetingPolicyPSTN.AllowPSTNUsersToBypassLobby - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.5.4" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure users dialing in can't bypass the lobby" - $auditResult.Result = $PSTNBypassDisabled - $auditResult.Details = "AllowPSTNUsersToBypassLobby is set to $($CsTeamsMeetingPolicyPSTN.AllowPSTNUsersToBypassLobby)" - $auditResult.FailureReason = if ($PSTNBypassDisabled) { "N/A" } else { "Users dialing in can bypass the lobby" } - $auditResult.Status = if ($PSTNBypassDisabled) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $PSTNBypassDisabled) { + "Users dialing in can bypass the lobby" + } + else { + "N/A" + } - $auditResults += $auditResult + $details = if ($PSTNBypassDisabled) { + "AllowPSTNUsersToBypassLobby is set to False" + } + else { + "AllowPSTNUsersToBypassLobby is set to True" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "8.5.4" + Result = $PSTNBypassDisabled + Status = if ($PSTNBypassDisabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-DisallowInfectedFilesDownload.ps1 b/source/tests/Test-DisallowInfectedFilesDownload.ps1 index f3c5f91..3ce9b3a 100644 --- a/source/tests/Test-DisallowInfectedFilesDownload.ps1 +++ b/source/tests/Test-DisallowInfectedFilesDownload.ps1 @@ -1,41 +1,53 @@ function Test-DisallowInfectedFilesDownload { [CmdletBinding()] param ( - # Define your parameters here + # Aligned + # Define your parameters here if needed ) begin { - # Initialization code + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 - $auditResult = [CISAuditResult]::new() + # Initialization code, if needed } 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 - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "10.1" - $auditResult.CISDescription = "Deploy and Maintain Anti-Malware Software" + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isDisallowInfectedFileDownloadEnabled) { + "Downloading infected files is not disallowed." + } + else { + "N/A" + } - $auditResult.Rec = "7.3.1" - $auditResult.ELevel = "E5" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure Office 365 SharePoint infected files are disallowed for download" + $details = if ($isDisallowInfectedFileDownloadEnabled) { + "DisallowInfectedFileDownload: True" + } + else { + "DisallowInfectedFileDownload: False" + } + + # 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 - $auditResult.Result = $isDisallowInfectedFileDownloadEnabled - $auditResult.Details = "DisallowInfectedFileDownload: $($SPOTenantDisallowInfectedFileDownload.DisallowInfectedFileDownload)" - $auditResult.FailureReason = if (-not $isDisallowInfectedFileDownloadEnabled) { "Downloading infected files is not disallowed." } else { "N/A" } - $auditResult.Status = if ($isDisallowInfectedFileDownloadEnabled) { "Pass" } else { "Fail" } } end { - # Return auditResult + # Return the audit result return $auditResult } } diff --git a/source/tests/Test-EnableDKIM.ps1 b/source/tests/Test-EnableDKIM.ps1 index a0b5da9..db7bac6 100644 --- a/source/tests/Test-EnableDKIM.ps1 +++ b/source/tests/Test-EnableDKIM.ps1 @@ -1,44 +1,52 @@ function Test-EnableDKIM { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 2.1.9 (L1) Ensure DKIM is enabled for all Exchange Online Domains - # Pass if Enabled is True for all domains. Fail if any domain has Enabled set to False. + + # Retrieve DKIM configuration for all domains $dkimConfig = Get-DkimSigningConfig | Select-Object Domain, Enabled $dkimResult = ($dkimConfig | ForEach-Object { $_.Enabled }) -notcontains $false $dkimFailedDomains = $dkimConfig | Where-Object { -not $_.Enabled } | ForEach-Object { $_.Domain } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($dkimResult) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "2.1.9" - $auditResult.RecDescription = "Ensure that DKIM is enabled for all Exchange Online Domains" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "9.5" - $auditResult.CISDescription = "Implement DMARC" - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $dkimResult - $auditResult.Details = if (-not $dkimResult) { "DKIM not enabled for: $($dkimFailedDomains -join ', ')" } else { "All domains have DKIM enabled" } - $auditResult.FailureReason = if (-not $dkimResult) { "DKIM is not enabled for some domains" } else { "N/A" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $dkimResult) { + "DKIM is not enabled for some domains" + } + else { + "N/A" + } - $auditResults += $auditResult + $details = if ($dkimResult) { + "All domains have DKIM enabled" + } + else { + "DKIM not enabled for: $($dkimFailedDomains -join ', ')" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "2.1.9" + Result = $dkimResult + Status = if ($dkimResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } -} \ No newline at end of file +} diff --git a/source/tests/Test-ExternalNoControl.ps1 b/source/tests/Test-ExternalNoControl.ps1 index aa5978f..8d52da7 100644 --- a/source/tests/Test-ExternalNoControl.ps1 +++ b/source/tests/Test-ExternalNoControl.ps1 @@ -1,45 +1,52 @@ function Test-ExternalNoControl { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 - $auditResults = @() + # Initialization code, if needed } process { # 8.5.7 (L1) Ensure external participants can't give or request control - # Connect to Teams PowerShell using Connect-MicrosoftTeams - + # Retrieve Teams meeting policy for external participant control $CsTeamsMeetingPolicyControl = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowExternalParticipantGiveRequestControl $externalControlRestricted = -not $CsTeamsMeetingPolicyControl.AllowExternalParticipantGiveRequestControl - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.5.7" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure external participants can't give or request control" - $auditResult.Result = $externalControlRestricted - $auditResult.Details = "AllowExternalParticipantGiveRequestControl is set to $($CsTeamsMeetingPolicyControl.AllowExternalParticipantGiveRequestControl)" - $auditResult.FailureReason = if ($externalControlRestricted) { "N/A" } else { "External participants can give or request control" } - $auditResult.Status = if ($externalControlRestricted) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $externalControlRestricted) { + "External participants can give or request control" + } + else { + "N/A" + } - $auditResults += $auditResult + $details = if ($externalControlRestricted) { + "AllowExternalParticipantGiveRequestControl is set to False" + } + else { + "AllowExternalParticipantGiveRequestControl is set to True" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "8.5.7" + Result = $externalControlRestricted + Status = if ($externalControlRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-ExternalSharingCalendars.ps1 b/source/tests/Test-ExternalSharingCalendars.ps1 index d721a14..9053bbb 100644 --- a/source/tests/Test-ExternalSharingCalendars.ps1 +++ b/source/tests/Test-ExternalSharingCalendars.ps1 @@ -1,17 +1,21 @@ function Test-ExternalSharingCalendars { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - # Dot source the class script + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 - $auditResults = @() + # Initialization code, if needed } 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*' } # Check if calendar sharing is disabled in all applicable policies @@ -24,30 +28,34 @@ function Test-ExternalSharingCalendars { } } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Rec = "1.3.3" - $auditResult.RecDescription = "Ensure 'External sharing' of calendars is not available" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - # The following IG values are placeholders. Replace with actual values when known. - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.CISControlVer = "v8" - # Placeholder for CIS Control, to be replaced with the actual value when available - $auditResult.CISControl = "4.8" - $auditResult.CISDescription = "Uninstall or Disable Unnecessary Services on Enterprise Assets and Software" - $auditResult.Result = $isExternalSharingDisabled - $auditResult.Details = if ($isExternalSharingDisabled) { "Calendar sharing with external users is disabled." } else { "Enabled Sharing Policies: $($sharingPolicyDetails -join ', ')" } - $auditResult.FailureReason = if ($isExternalSharingDisabled) { "N/A" } else { "Calendar sharing with external users is enabled in one or more policies." } - $auditResult.Status = if ($isExternalSharingDisabled) { "Pass" } else { "Fail" } + # 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" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-GlobalAdminsCount.ps1 b/source/tests/Test-GlobalAdminsCount.ps1 index f79b04e..c57110f 100644 --- a/source/tests/Test-GlobalAdminsCount.ps1 +++ b/source/tests/Test-GlobalAdminsCount.ps1 @@ -1,46 +1,52 @@ function Test-GlobalAdminsCount { [CmdletBinding()] param ( - # Define your parameters here + # Aligned + # Define your parameters here if needed ) begin { - # Dot source the class script + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 - $auditResults = @() + # Initialization code, if needed } process { # 1.1.3 (L1) Ensure that between two and four global admins are designated - # Pass if the count of global admins is between 2 and 4. Fail otherwise. + # 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 ', ' - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "5.1" - $auditResult.CISDescription = "Establish and Maintain an Inventory of Accounts" - $auditResult.Rec = "1.1.3" - $auditResult.ELevel = "E3" # Based on your environment (E3, E5, etc.) - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $true # Set based on the benchmark - $auditResult.IG2 = $true # Set based on the benchmark - $auditResult.IG3 = $true # Set based on the benchmark - $auditResult.RecDescription = "Ensure that between two and four global admins are designated" - $auditResult.Result = $globalAdminCount -ge 2 -and $globalAdminCount -le 4 - $auditResult.Details = "Count: $globalAdminCount; Users: $globalAdminUsernames" - $auditResult.FailureReason = if ($globalAdminCount -lt 2) { "Less than 2 global admins: $globalAdminUsernames" } elseif ($globalAdminCount -gt 4) { "More than 4 global admins: $globalAdminUsernames" } else { "N/A" } - $auditResult.Status = if ($globalAdminCount -ge 2 -and $globalAdminCount -le 4) { "Pass" } else { "Fail" } + # 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" + } - $auditResults += $auditResult + $details = "Count: $globalAdminCount; Users: $globalAdminUsernames" + + # 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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-GuestAccessExpiration.ps1 b/source/tests/Test-GuestAccessExpiration.ps1 index fb9b8cb..4a0b2b6 100644 --- a/source/tests/Test-GuestAccessExpiration.ps1 +++ b/source/tests/Test-GuestAccessExpiration.ps1 @@ -1,41 +1,47 @@ function Test-GuestAccessExpiration { [CmdletBinding()] param ( - # Define your parameters here + # Aligned + # Define your parameters here if needed ) begin { - # Initialization code + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 - $auditResult = [CISAuditResult]::new() + # Initialization code, if needed } process { # 7.2.9 (L1) Ensure guest access to a site or OneDrive will expire automatically + + # Retrieve SharePoint tenant settings related to guest access expiration $SPOTenantGuestAccess = Get-SPOTenant | Select-Object ExternalUserExpirationRequired, ExternalUserExpireInDays $isGuestAccessExpirationConfiguredCorrectly = $SPOTenantGuestAccess.ExternalUserExpirationRequired -and $SPOTenantGuestAccess.ExternalUserExpireInDays -le 30 - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" - $auditResult.CISDescription = "Explicitly Not Mapped" + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $isGuestAccessExpirationConfiguredCorrectly) { + "Guest access expiration is not configured to automatically expire within 30 days or less." + } + else { + "N/A" + } - $auditResult.Rec = "7.2.9" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.RecDescription = "Ensure guest access to a site or OneDrive will expire automatically" + $details = "ExternalUserExpirationRequired: $($SPOTenantGuestAccess.ExternalUserExpirationRequired); ExternalUserExpireInDays: $($SPOTenantGuestAccess.ExternalUserExpireInDays)" - $auditResult.Result = $isGuestAccessExpirationConfiguredCorrectly - $auditResult.Details = "ExternalUserExpirationRequired: $($SPOTenantGuestAccess.ExternalUserExpirationRequired); ExternalUserExpireInDays: $($SPOTenantGuestAccess.ExternalUserExpireInDays)" - $auditResult.FailureReason = if (-not $isGuestAccessExpirationConfiguredCorrectly) { "Guest access expiration is not configured to automatically expire within 30 days or less." } else { "N/A" } - $auditResult.Status = if ($isGuestAccessExpirationConfiguredCorrectly) { "Pass" } else { "Fail" } + # Create and populate the CISAuditResult object + $params = @{ + Rec = "7.2.9" + Result = $isGuestAccessExpirationConfiguredCorrectly + Status = if ($isGuestAccessExpirationConfiguredCorrectly) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResult + # Return the audit result return $auditResult } } diff --git a/source/tests/Test-GuestUsersBiweeklyReview.ps1 b/source/tests/Test-GuestUsersBiweeklyReview.ps1 index b89ae85..730f039 100644 --- a/source/tests/Test-GuestUsersBiweeklyReview.ps1 +++ b/source/tests/Test-GuestUsersBiweeklyReview.ps1 @@ -1,61 +1,54 @@ function Test-GuestUsersBiweeklyReview { [CmdletBinding()] - param () + param ( + # Aligned + # Define your parameters here if needed + ) begin { + # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 - $auditResults = @() + + # Initialization code, if needed } process { # 1.1.4 (L1) Ensure Guest Users are reviewed at least biweekly - # The function will fail if guest users are found since they should be reviewed manually biweekly. - try { - # Connect to Microsoft Graph - placeholder for connection command - # Connect-MgGraph -Scopes "User.Read.All" - $guestUsers = Get-MgUser -All -Filter "UserType eq 'Guest'" - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControl = "5.1, 5.3" - $auditResult.CISDescription = "Establish and Maintain an Inventory of Accounts, Disable Dormant Accounts" - $auditResult.Rec = "1.1.4" - $auditResult.RecDescription = "Ensure Guest Users are reviewed at least biweekly" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.CISControlVer = 'v8' + # Retrieve guest users from Microsoft Graph + # Connect-MgGraph -Scopes "User.Read.All" + $guestUsers = Get-MgUser -All -Filter "UserType eq 'Guest'" - if ($guestUsers) { - $auditCommand = "Get-MgUser -All -Property UserType,UserPrincipalName | Where {`$_.UserType -ne 'Member'} | Format-Table UserPrincipalName, UserType" - $auditResult.Status = "Fail" - $auditResult.Result = $false - $auditResult.Details = "Manual review required. To list guest users, run: `"$auditCommand`"." - $auditResult.FailureReason = "Guest users present: $($guestUsers.Count)" - } else { - $auditResult.Status = "Pass" - $auditResult.Result = $true - $auditResult.Details = "No guest users found." - $auditResult.FailureReason = "N/A" - } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($guestUsers) { + "Guest users present: $($guestUsers.Count)" } - catch { - $auditResult.Status = "Error" - $auditResult.Result = $false - $auditResult.Details = "Error while attempting to check guest users. Error message: $($_.Exception.Message)" - $auditResult.FailureReason = "An error occurred during the audit check." + else { + "N/A" } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } - - diff --git a/source/tests/Test-IdentifyExternalEmail.ps1 b/source/tests/Test-IdentifyExternalEmail.ps1 index 9c421c0..623d986 100644 --- a/source/tests/Test-IdentifyExternalEmail.ps1 +++ b/source/tests/Test-IdentifyExternalEmail.ps1 @@ -1,45 +1,47 @@ function Test-IdentifyExternalEmail { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 - $auditResults = @() + # Initialization code, if needed } process { # 6.2.3 (L1) Ensure email from external senders is identified - # Requirement is to have external sender tagging enabled - # Review + # Retrieve external sender tagging configuration $externalInOutlook = Get-ExternalInOutlook $externalTaggingEnabled = ($externalInOutlook | ForEach-Object { $_.Enabled }) -contains $true - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($externalTaggingEnabled) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "6.2.3" - $auditResult.RecDescription = "Ensure email from external senders is identified" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.Result = $externalTaggingEnabled - $auditResult.Details = "Enabled: $($externalTaggingEnabled); AllowList: $($externalInOutlook.AllowList)" - $auditResult.FailureReason = if (-not $externalTaggingEnabled) { "External sender tagging is disabled" } else { "N/A" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $externalTaggingEnabled) { + "External sender tagging is disabled" + } + else { + "N/A" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-LinkSharingRestrictions.ps1 b/source/tests/Test-LinkSharingRestrictions.ps1 index b0c14b0..b117da3 100644 --- a/source/tests/Test-LinkSharingRestrictions.ps1 +++ b/source/tests/Test-LinkSharingRestrictions.ps1 @@ -1,42 +1,47 @@ function Test-LinkSharingRestrictions { [CmdletBinding()] param ( + # Aligned # Define your parameters here # Test behavior in prod ) begin { - # Initialization code - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 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 + $isLinkSharingRestricted = $SPOTenantLinkSharing.DefaultSharingLinkType -eq 'Direct' # Or 'SpecificPeople' as per the recommendation - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" + # 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" + } - $auditResult.Rec = "7.2.7" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure link sharing is restricted in SharePoint and OneDrive" + $details = "DefaultSharingLinkType: $($SPOTenantLinkSharing.DefaultSharingLinkType)" - $auditResult.Result = $isLinkSharingRestricted - $auditResult.Details = "DefaultSharingLinkType: $($SPOTenantLinkSharing.DefaultSharingLinkType)" - $auditResult.FailureReason = if (-not $isLinkSharingRestricted) { "Link sharing is not restricted to 'Specific people'. Current setting: $($SPOTenantLinkSharing.DefaultSharingLinkType)" } else { "N/A" } - $auditResult.Status = if ($isLinkSharingRestricted) { "Pass" } else { "Fail" } + # Create and populate the CISAuditResult object + $params = @{ + Rec = "7.2.7" + Result = $isLinkSharingRestricted + Status = if ($isLinkSharingRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResult + # Return the audit result return $auditResult } } diff --git a/source/tests/Test-MailTipsEnabled.ps1 b/source/tests/Test-MailTipsEnabled.ps1 index 9a2efba..12224c0 100644 --- a/source/tests/Test-MailTipsEnabled.ps1 +++ b/source/tests/Test-MailTipsEnabled.ps1 @@ -1,43 +1,54 @@ function Test-MailTipsEnabled { [CmdletBinding()] param ( - # Define your parameters here + # Aligned + # Parameters can be added if needed ) begin { - # Initialization code + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $auditResult = [CISAuditResult]::new() } process { # 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 - # Since there is no direct CIS Control mapping, the control will be set as not applicable. - $auditResult.CISControl = "0" - $auditResult.CISControlVer = "v8" - $auditResult.CISDescription = "Explicitly Not Mapped" + # 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" + } - $auditResult.Rec = "6.5.2" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.RecDescription = "Ensure MailTips are enabled for end users" + $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." + } - $auditResult.Result = $allTipsEnabled -and $externalRecipientsTipsEnabled - $auditResult.Details = "MailTipsAllTipsEnabled: $($orgConfig.MailTipsAllTipsEnabled); MailTipsExternalRecipientsTipsEnabled: $($orgConfig.MailTipsExternalRecipientsTipsEnabled); MailTipsGroupMetricsEnabled: $($orgConfig.MailTipsGroupMetricsEnabled); MailTipsLargeAudienceThreshold: $($orgConfig.MailTipsLargeAudienceThreshold)" - $auditResult.FailureReason = if (-not $auditResult.Result) { "One or more MailTips settings are not configured as required." } else { "N/A" } - $auditResult.Status = if ($auditResult.Result) { "Pass" } else { "Fail" } + # 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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResult + # Return the audit result return $auditResult } } - diff --git a/source/tests/Test-MailboxAuditingE3.ps1 b/source/tests/Test-MailboxAuditingE3.ps1 index f37bd65..79373b7 100644 --- a/source/tests/Test-MailboxAuditingE3.ps1 +++ b/source/tests/Test-MailboxAuditingE3.ps1 @@ -1,26 +1,20 @@ function Test-MailboxAuditingE3 { [CmdletBinding()] param ( + # Aligned + # Create Table for Details # Parameters can be added if needed ) begin { + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 $e3SkuPartNumbers = @("ENTERPRISEPACK", "OFFICESUBSCRIPTION") $AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") $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") - $auditResult = [CISAuditResult]::new() - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "6.1.2" - $auditResult.RecDescription = "Ensure mailbox auditing for Office E3 users is Enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "8.2" - $auditResult.CISDescription = "Collect audit logs." - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true + $allFailures = @() $allUsers = Get-AzureADUser -All $true @@ -72,10 +66,19 @@ function Test-MailboxAuditingE3 { } } - $auditResult.Result = $allFailures.Count -eq 0 - $auditResult.Status = if ($auditResult.Result) { "Pass" } else { "Fail" } - $auditResult.Details = if ($auditResult.Result) { "All Office E3 users have correct mailbox audit settings." } else { $allFailures -join " | " } - $auditResult.FailureReason = if (-not $auditResult.Result) { "Audit issues detected." } else { "N/A" } + # 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 } end { diff --git a/source/tests/Test-MailboxAuditingE5.ps1 b/source/tests/Test-MailboxAuditingE5.ps1 index a2ee587..8f6796c 100644 --- a/source/tests/Test-MailboxAuditingE5.ps1 +++ b/source/tests/Test-MailboxAuditingE5.ps1 @@ -1,23 +1,21 @@ function Test-MailboxAuditingE5 { [CmdletBinding()] - param () + param ( + # Aligned + # Create Table for Details + # Parameters can be added if needed + ) begin { + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + $e5SkuPartNumbers = @("SPE_E5", "ENTERPRISEPREMIUM", "OFFICEE5") $AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") $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") - $auditResult = [CISAuditResult]::new() - $auditResult.ELevel = "E5" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "6.1.3" - $auditResult.RecDescription = "Ensure mailbox auditing for Office E5 users is Enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "8.2" - $auditResult.CISDescription = "Collect audit logs." - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true + + $allFailures = @() $allUsers = Get-AzureADUser -All $true @@ -31,15 +29,11 @@ function Test-MailboxAuditingE5 { } try { - # Define SKU Part Numbers for Office E5 licenses - # Define SKU Part Numbers for Office E5 licenses - $e5SkuPartNumbers = @("SPE_E5", "ENTERPRISEPREMIUM", "OFFICEE5") $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 $missingActions = @() @@ -78,13 +72,19 @@ function Test-MailboxAuditingE5 { } } - if ($allFailures.Count -eq 0) { - Write-Verbose "All evaluated E5 users have correct mailbox audit settings." + # 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 = "6.1.3" + Result = $allFailures.Count -eq 0 + Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons } - $auditResult.Result = $allFailures.Count -eq 0 - $auditResult.Status = if ($auditResult.Result) { "Pass" } else { "Fail" } - $auditResult.Details = if ($auditResult.Result) { "All Office E5 users have correct mailbox audit settings." } else { $allFailures -join " | " } - $auditResult.FailureReason = if (-not $auditResult.Result) { "Audit issues detected." } else { "N/A" } + $auditResult = Initialize-CISAuditResult @params } end { @@ -117,4 +117,4 @@ function Format-MissingActions { } return $formattedResults -join '; ' -} \ No newline at end of file +} diff --git a/source/tests/Test-ManagedApprovedPublicGroups.ps1 b/source/tests/Test-ManagedApprovedPublicGroups.ps1 index b7b708d..80fb4fa 100644 --- a/source/tests/Test-ManagedApprovedPublicGroups.ps1 +++ b/source/tests/Test-ManagedApprovedPublicGroups.ps1 @@ -1,54 +1,52 @@ function Test-ManagedApprovedPublicGroups { [CmdletBinding()] param ( - # Define your parameters here + # Aligned + # Parameters can be added if needed ) begin { - # Dot source the class script + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed - $auditResults = @() } process { # 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 - # Check if there are public groups and if they are organizationally managed/approved - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" - $auditResult.Rec = "1.2.1" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true # Based on the provided CIS Control image, IG3 is not applicable - $auditResult.RecDescription = "Ensure that only organizationally managed/approved public groups exist" + # 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" + } - if ($null -eq $allGroups -or $allGroups.Count -eq 0) { - $auditResult.Result = $true - $auditResult.Details = "No public groups found." - $auditResult.FailureReason = "N/A" - $auditResult.Status = "Pass" + $details = if ($null -eq $allGroups -or $allGroups.Count -eq 0) { + "No public groups found." } else { $groupDetails = $allGroups | ForEach-Object { $_.DisplayName + " (" + $_.Visibility + ")" } - $detailsString = $groupDetails -join ', ' - - $auditResult.Result = $false - $auditResult.Details = "Public groups found: $detailsString" - $auditResult.FailureReason = "There are public groups present that are not organizationally managed/approved." - $auditResult.Status = "Fail" + "Public groups found: $($groupDetails -join ', ')" } - $auditResults += $auditResult + # 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 + } + $auditResult = Initialize-CISAuditResult @params } end { # Return auditResults - return $auditResults + return $auditResult } } diff --git a/source/tests/Test-MeetingChatNoAnonymous.ps1 b/source/tests/Test-MeetingChatNoAnonymous.ps1 index b75835a..29428b1 100644 --- a/source/tests/Test-MeetingChatNoAnonymous.ps1 +++ b/source/tests/Test-MeetingChatNoAnonymous.ps1 @@ -1,46 +1,48 @@ function Test-MeetingChatNoAnonymous { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 8.5.5 (L2) Ensure meeting chat does not allow anonymous users - # Name doesn't match profile level in benchmarks either. # 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' - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.5.5" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure meeting chat does not allow anonymous users" - $auditResult.Result = $chatAnonDisabled - $auditResult.Details = "MeetingChatEnabledType is set to $($CsTeamsMeetingPolicyChat.MeetingChatEnabledType)" - $auditResult.FailureReason = if ($chatAnonDisabled) { "N/A" } else { "Meeting chat allows anonymous users" } - $auditResult.Status = if ($chatAnonDisabled) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($chatAnonDisabled) { + "N/A" + } + else { + "Meeting chat allows anonymous users" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-ModernAuthExchangeOnline.ps1 b/source/tests/Test-ModernAuthExchangeOnline.ps1 index db0c8af..811679b 100644 --- a/source/tests/Test-ModernAuthExchangeOnline.ps1 +++ b/source/tests/Test-ModernAuthExchangeOnline.ps1 @@ -1,40 +1,42 @@ function Test-ModernAuthExchangeOnline { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - - $auditResults = [CISAuditResult]::new() - # Initialization code + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { try { # Ensuring the ExchangeOnlineManagement module is available - # 6.5.1 (L1) Ensure modern authentication for Exchange Online is enabled $orgConfig = Get-OrganizationConfig | Select-Object -Property Name, OAuth2ClientProfileEnabled - # Create an instance of CISAuditResult and populate it + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $orgConfig.OAuth2ClientProfileEnabled) { + "Modern authentication is disabled" + } + else { + "N/A" + } - $auditResults.CISControlVer = "v8" - $auditResults.CISControl = "3.10" - $auditResults.CISDescription = "Encrypt Sensitive Data in Transit" - $auditResults.IG1 = $false # As per CIS Control v8 mapping for IG1 - $auditResults.IG2 = $true # As per CIS Control v8 mapping for IG2 - $auditResults.IG3 = $true # As per CIS Control v8 mapping for IG3 - $auditResults.ELevel = "E3" # Based on your environment (E3, E5, etc.) - $auditResults.ProfileLevel = "L1" - $auditResults.Rec = "6.5.1" - $auditResults.RecDescription = "Ensure modern authentication for Exchange Online is enabled (Automated)" - $auditResults.Result = $orgConfig.OAuth2ClientProfileEnabled - $auditResults.Details = $auditResults.Details = $orgConfig.Name + " OAuth2ClientProfileEnabled: " + $orgConfig.OAuth2ClientProfileEnabled - $auditResults.FailureReason = if (-not $orgConfig.OAuth2ClientProfileEnabled) { "Modern authentication is disabled" } else { "N/A" } - $auditResults.Status = if ($orgConfig.OAuth2ClientProfileEnabled) { "Pass" } else { "Fail" } + $details = "OAuth2ClientProfileEnabled: $($orgConfig.OAuth2ClientProfileEnabled) for Organization: $($orgConfig.Name)" + # 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 + } + $auditResult = Initialize-CISAuditResult @params } catch { @@ -43,12 +45,7 @@ function Test-ModernAuthExchangeOnline { } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } - - - - - diff --git a/source/tests/Test-ModernAuthSharePoint.ps1 b/source/tests/Test-ModernAuthSharePoint.ps1 index 0677c3a..3f7ae76 100644 --- a/source/tests/Test-ModernAuthSharePoint.ps1 +++ b/source/tests/Test-ModernAuthSharePoint.ps1 @@ -1,13 +1,14 @@ function Test-ModernAuthSharePoint { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { @@ -15,25 +16,29 @@ function Test-ModernAuthSharePoint { $SPOTenant = Get-SPOTenant | Select-Object -Property LegacyAuthProtocolsEnabled $modernAuthForSPRequired = -not $SPOTenant.LegacyAuthProtocolsEnabled - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.10" - $auditResult.CISDescription = "Encrypt Sensitive Data in Transit" - $auditResult.Rec = "7.2.1" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Modern Authentication for SharePoint Applications" - $auditResult.Result = $modernAuthForSPRequired - $auditResult.Details = "LegacyAuthProtocolsEnabled: $($SPOTenant.LegacyAuthProtocolsEnabled)" - $auditResult.FailureReason = if (-not $modernAuthForSPRequired) { "Legacy authentication protocols are enabled" } else { "N/A" } - $auditResult.Status = if ($modernAuthForSPRequired) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $modernAuthForSPRequired) { + "Legacy authentication protocols are enabled" + } + else { + "N/A" + } + + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResult + # Return the audit result return $auditResult } } diff --git a/source/tests/Test-NoAnonymousMeetingJoin.ps1 b/source/tests/Test-NoAnonymousMeetingJoin.ps1 index b72c2f4..fbeb7dd 100644 --- a/source/tests/Test-NoAnonymousMeetingJoin.ps1 +++ b/source/tests/Test-NoAnonymousMeetingJoin.ps1 @@ -1,13 +1,14 @@ function Test-NoAnonymousMeetingJoin { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { @@ -18,28 +19,29 @@ function Test-NoAnonymousMeetingJoin { $teamsMeetingPolicy = Get-CsTeamsMeetingPolicy -Identity Global $allowAnonymousUsersToJoinMeeting = $teamsMeetingPolicy.AllowAnonymousUsersToJoinMeeting - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # The control is Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.5.1" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure anonymous users can't join a meeting" - $auditResult.Result = -not $allowAnonymousUsersToJoinMeeting - $auditResult.Details = "AllowAnonymousUsersToJoinMeeting is set to $allowAnonymousUsersToJoinMeeting" - $auditResult.FailureReason = if ($allowAnonymousUsersToJoinMeeting) { "Anonymous users are allowed to join meetings" } else { "N/A" } - $auditResult.Status = if (-not $allowAnonymousUsersToJoinMeeting) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($allowAnonymousUsersToJoinMeeting) { + "Anonymous users are allowed to join meetings" + } + else { + "N/A" + } - $auditResults += $auditResult + $details = "AllowAnonymousUsersToJoinMeeting is set to $allowAnonymousUsersToJoinMeeting" + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "8.5.1" + Result = -not $allowAnonymousUsersToJoinMeeting + Status = if (-not $allowAnonymousUsersToJoinMeeting) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-NoAnonymousMeetingStart.ps1 b/source/tests/Test-NoAnonymousMeetingStart.ps1 index 4d5a432..01c680f 100644 --- a/source/tests/Test-NoAnonymousMeetingStart.ps1 +++ b/source/tests/Test-NoAnonymousMeetingStart.ps1 @@ -1,13 +1,14 @@ function Test-NoAnonymousMeetingStart { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { @@ -18,28 +19,29 @@ function Test-NoAnonymousMeetingStart { $CsTeamsMeetingPolicyAnonymous = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowAnonymousUsersToStartMeeting $anonymousStartDisabled = -not $CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.5.2" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure anonymous users and dial-in callers can't start a meeting" - $auditResult.Result = $anonymousStartDisabled - $auditResult.Details = "AllowAnonymousUsersToStartMeeting is set to $($CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting)" - $auditResult.FailureReason = if ($anonymousStartDisabled) { "N/A" } else { "Anonymous users and dial-in callers can start a meeting" } - $auditResult.Status = if ($anonymousStartDisabled) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($anonymousStartDisabled) { + "N/A" + } + else { + "Anonymous users and dial-in callers can start a meeting" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-NoWhitelistDomains.ps1 b/source/tests/Test-NoWhitelistDomains.ps1 index b290dca..820ff7b 100644 --- a/source/tests/Test-NoWhitelistDomains.ps1 +++ b/source/tests/Test-NoWhitelistDomains.ps1 @@ -1,43 +1,47 @@ function Test-NoWhitelistDomains { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 6.2.2 (L1) Ensure mail transport rules do not whitelist specific domains - $whitelistedRules = Get-TransportRule | Where-Object { $_.SetSCL -eq -1 -and $_.SenderDomainIs -ne $null } - $auditResult.CISControl = "0.0" - $auditResult.CISControlVer = "v8" - $auditResult.CISDescription = "Explicitly Not Mapped" + # Retrieve transport rules that whitelist specific domains + $whitelistedRules = Get-TransportRule | Where-Object { $_.SetSCL -eq -1 -and $null -ne $_.SenderDomainIs } - $auditResult.Rec = "6.2.2" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.RecDescription = "Ensure mail transport rules do not whitelist specific domains" - - if ($whitelistedRules) { - $ruleDetails = $whitelistedRules | ForEach-Object { "{0}: {1}" -f $_.Name, ($_.SenderDomainIs -join ', ') } - $auditResult.Result = $false - $auditResult.Details = "Whitelisted Rules: $($ruleDetails -join '; ')" - $auditResult.FailureReason = "There are transport rules whitelisting specific domains." - $auditResult.Status = "Fail" - } else { - $auditResult.Result = $true - $auditResult.Details = "No transport rules whitelisting specific domains found." - $auditResult.FailureReason = "N/A" - $auditResult.Status = "Pass" + # 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." + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "6.2.2" + Result = -not $whitelistedRules + Status = if ($whitelistedRules) { "Fail" } else { "Pass" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-NotifyMalwareInternal.ps1 b/source/tests/Test-NotifyMalwareInternal.ps1 index 90e7f74..ba962d6 100644 --- a/source/tests/Test-NotifyMalwareInternal.ps1 +++ b/source/tests/Test-NotifyMalwareInternal.ps1 @@ -1,12 +1,14 @@ function Test-NotifyMalwareInternal { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { @@ -24,31 +26,35 @@ function Test-NotifyMalwareInternal { # Determine the result based on the presence of custom policies without notifications $result = $policiesToReport.Count -eq 0 - $details = if ($result) { "All custom malware policies have notifications enabled." } else { "Misconfigured Policies: $($policiesToReport -join ', ')" } - $failureReason = if ($result) { "N/A" } else { "Some custom policies do not have notifications for internal users sending malware enabled." } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($result) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "2.1.3" - $auditResult.RecDescription = "Ensure notifications for internal users sending malware is Enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "17.5" - $auditResult.CISDescription = "Assign Key Roles and Responsibilities" - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $result - $auditResult.Details = $details - $auditResult.FailureReason = $failureReason + # 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." + } - $auditResults += $auditResult + $details = if ($result) { + "All custom malware policies have notifications enabled." + } + else { + "Misconfigured Policies: $($policiesToReport -join ', ')" + } + + # Create and populate the CISAuditResult object + $params = @{ + Rec = "2.1.3" + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-OneDriveContentRestrictions.ps1 b/source/tests/Test-OneDriveContentRestrictions.ps1 index 2a610ca..7a69c37 100644 --- a/source/tests/Test-OneDriveContentRestrictions.ps1 +++ b/source/tests/Test-OneDriveContentRestrictions.ps1 @@ -1,37 +1,47 @@ function Test-OneDriveContentRestrictions { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 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' - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" + # 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" + } - $auditResult.Rec = "7.2.4" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure OneDrive content sharing is restricted" + $details = if ($isOneDriveSharingRestricted) { + "OneDrive content sharing is restricted." + } + else { + "OneDriveSharingCapability: $($SPOTenant.OneDriveSharingCapability)" + } - $auditResult.Result = $isOneDriveSharingRestricted - $auditResult.Details = "OneDriveSharingCapability: $($SPOTenant.OneDriveSharingCapability)" - $auditResult.FailureReason = if (-not $isOneDriveSharingRestricted) { "OneDrive content sharing is not restricted to 'Disabled'. Current setting: $($SPOTenant.OneDriveSharingCapability)" } else { "N/A" } - $auditResult.Status = if ($isOneDriveSharingRestricted) { "Pass" } else { "Fail" } + # Create and populate the CISAuditResult object + $params = @{ + Rec = "7.2.4" + Result = $isOneDriveSharingRestricted + Status = if ($isOneDriveSharingRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-OneDriveSyncRestrictions.ps1 b/source/tests/Test-OneDriveSyncRestrictions.ps1 index 5b3ca53..5357cda 100644 --- a/source/tests/Test-OneDriveSyncRestrictions.ps1 +++ b/source/tests/Test-OneDriveSyncRestrictions.ps1 @@ -1,37 +1,47 @@ function Test-OneDriveSyncRestrictions { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 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 - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" - $auditResult.CISDescription = "Explicitly Not Mapped" + # 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" + } - $auditResult.Rec = "7.3.2" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.RecDescription = "Ensure OneDrive sync is restricted for unmanaged devices" + $details = if ($isSyncRestricted) { + "OneDrive sync is restricted for unmanaged devices." + } + else { + "TenantRestrictionEnabled: $($SPOTenantSyncClientRestriction.TenantRestrictionEnabled); AllowedDomainList: $($SPOTenantSyncClientRestriction.AllowedDomainList -join ', ')" + } - $auditResult.Result = $isSyncRestricted - $auditResult.Details = "TenantRestrictionEnabled: $($SPOTenantSyncClientRestriction.TenantRestrictionEnabled); AllowedDomainList: $($SPOTenantSyncClientRestriction.AllowedDomainList -join ', ')" - $auditResult.FailureReason = 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" } - $auditResult.Status = if ($isSyncRestricted) { "Pass" } else { "Fail" } + # Create and populate the CISAuditResult object + $params = @{ + Rec = "7.3.2" + Result = $isSyncRestricted + Status = if ($isSyncRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-OrgOnlyBypassLobby.ps1 b/source/tests/Test-OrgOnlyBypassLobby.ps1 index 013fe6d..7a7e668 100644 --- a/source/tests/Test-OrgOnlyBypassLobby.ps1 +++ b/source/tests/Test-OrgOnlyBypassLobby.ps1 @@ -1,13 +1,14 @@ function Test-OrgOnlyBypassLobby { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { @@ -15,31 +16,38 @@ function Test-OrgOnlyBypassLobby { # 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' - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "6.8" - $auditResult.CISDescription = "Define and Maintain Role-Based Access Control" - $auditResult.Rec = "8.5.3" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $true # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure only people in my org can bypass the lobby" - $auditResult.Result = $lobbyBypassRestricted - $auditResult.Details = "AutoAdmittedUsers is set to $($CsTeamsMeetingPolicyLobby.AutoAdmittedUsers)" - $auditResult.FailureReason = if ($lobbyBypassRestricted) { "N/A" } else { "External participants can bypass the lobby" } - $auditResult.Status = if ($lobbyBypassRestricted) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $lobbyBypassRestricted) { + "External participants can bypass the lobby" + } + else { + "N/A" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-OrganizersPresent.ps1 b/source/tests/Test-OrganizersPresent.ps1 index 8bf8cd6..337e671 100644 --- a/source/tests/Test-OrganizersPresent.ps1 +++ b/source/tests/Test-OrganizersPresent.ps1 @@ -1,13 +1,14 @@ function Test-OrganizersPresent { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { @@ -15,31 +16,38 @@ function Test-OrganizersPresent { # 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' - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.5.6" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure only organizers and co-organizers can present" - $auditResult.Result = $presenterRoleRestricted - $auditResult.Details = "DesignatedPresenterRoleMode is set to $($CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode)" - $auditResult.FailureReason = if ($presenterRoleRestricted) { "N/A" } else { "Others besides organizers and co-organizers can present" } - $auditResult.Status = if ($presenterRoleRestricted) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $presenterRoleRestricted) { + "Others besides organizers and co-organizers can present" + } + else { + "N/A" + } - $auditResults += $auditResult + $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 = "8.5.6" + Result = $presenterRoleRestricted + Status = if ($presenterRoleRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-PasswordHashSync.ps1 b/source/tests/Test-PasswordHashSync.ps1 index df0acca..583d65e 100644 --- a/source/tests/Test-PasswordHashSync.ps1 +++ b/source/tests/Test-PasswordHashSync.ps1 @@ -1,43 +1,47 @@ function Test-PasswordHashSync { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments # Pass if OnPremisesSyncEnabled is True. Fail otherwise. - $passwordHashSync = Get-MgOrganization | Select-Object OnPremisesSyncEnabled - $hashSyncResult = $passwordHashSync.OnPremisesSyncEnabled - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($hashSyncResult) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "5.1.8.1" - $auditResult.RecDescription = "Ensure password hash sync is enabled for hybrid deployments" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "6.7" - $auditResult.CISDescription = "Centralize Access Control" - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $hashSyncResult - $auditResult.Details = "OnPremisesSyncEnabled: $($passwordHashSync.OnPremisesSyncEnabled)" - $auditResult.FailureReason = if (-not $hashSyncResult) { "Password hash sync for hybrid deployments is not enabled" } else { "N/A" } + # Retrieve password hash sync status + $passwordHashSync = Get-MgOrganization | Select-Object -ExpandProperty OnPremisesSyncEnabled + $hashSyncResult = $passwordHashSync - $auditResults += $auditResult + # 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 = "5.1.8.1" + Result = $hashSyncResult + Status = if ($hashSyncResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index 8faaf24..530d481 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -1,45 +1,47 @@ function Test-PasswordNeverExpirePolicy { [CmdletBinding()] param ( + # Aligned [Parameter(Mandatory)] [string]$DomainName # DomainName parameter is now mandatory ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } 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. + # Pass if PasswordValidityPeriodInDays is 0. Fail otherwise. - $passwordPolicy = Get-MgDomain -DomainId $DomainName | Select-Object PasswordValidityPeriodInDays + # Retrieve password expiration policy + $passwordPolicy = Get-MgDomain -DomainId $DomainName | Select-Object -ExpandProperty PasswordValidityPeriodInDays - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Rec = "1.3.1" - $auditResult.RecDescription = "Ensure the 'Password expiration policy' is set to 'Set passwords to never expire'" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "5.2" - $auditResult.CISDescription = "Use Unique Passwords" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true # All are true - $auditResult.Result = $passwordPolicy.PasswordValidityPeriodInDays -eq 0 - $auditResult.Details = "Validity Period: $($passwordPolicy.PasswordValidityPeriodInDays) days" - $auditResult.FailureReason = if ($passwordPolicy.PasswordValidityPeriodInDays -eq 0) { "N/A" } else { "Password expiration is not set to never expire" } - $auditResult.Status = if ($passwordPolicy.PasswordValidityPeriodInDays -eq 0) { "Pass" } else { "Fail" } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($passwordPolicy -ne 0) { + "Password expiration is not set to never expire" + } + else { + "N/A" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-ReauthWithCode.ps1 b/source/tests/Test-ReauthWithCode.ps1 index 9733868..28ac0f0 100644 --- a/source/tests/Test-ReauthWithCode.ps1 +++ b/source/tests/Test-ReauthWithCode.ps1 @@ -1,37 +1,42 @@ function Test-ReauthWithCode { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 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 - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" - $auditResult.CISDescription = "Explicitly Not Mapped" + # 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" + } - $auditResult.Rec = "7.2.10" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.RecDescription = "Ensure reauthentication with verification code is restricted" + $details = "EmailAttestationRequired: $($SPOTenantReauthentication.EmailAttestationRequired); EmailAttestationReAuthDays: $($SPOTenantReauthentication.EmailAttestationReAuthDays)" - $auditResult.Result = $isReauthenticationRestricted - $auditResult.Details = "EmailAttestationRequired: $($SPOTenantReauthentication.EmailAttestationRequired); EmailAttestationReAuthDays: $($SPOTenantReauthentication.EmailAttestationReAuthDays)" - $auditResult.FailureReason = if (-not $isReauthenticationRestricted) { "Reauthentication with verification code does not require reauthentication within 15 days or less." } else { "N/A" } - $auditResult.Status = if ($isReauthenticationRestricted) { "Pass" } else { "Fail" } + # Create and populate the CISAuditResult object + $params = @{ + Rec = "7.2.10" + Result = $isReauthenticationRestricted + Status = if ($isReauthenticationRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-ReportSecurityInTeams.ps1 b/source/tests/Test-ReportSecurityInTeams.ps1 index f7ac954..f79cf17 100644 --- a/source/tests/Test-ReportSecurityInTeams.ps1 +++ b/source/tests/Test-ReportSecurityInTeams.ps1 @@ -1,21 +1,20 @@ function Test-ReportSecurityInTeams { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 8.6.1 (L1) Ensure users can report security concerns in Teams - # Connect to Teams PowerShell using Connect-MicrosoftTeams - # Connect to Exchange Online PowerShell using Connect-ExchangeOnline - + # 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 @@ -25,32 +24,33 @@ function Test-ReportSecurityInTeams { $ReportSubmissionPolicy.ReportPhishToCustomizedAddress -and $ReportSubmissionPolicy.ReportChatMessageToCustomizedAddressEnabled - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.6.1" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure users can report security concerns in Teams" - $auditResult.Result = $securityReportEnabled - $auditResult.Details = "AllowSecurityEndUserReporting: $($CsTeamsMessagingPolicy.AllowSecurityEndUserReporting); " + + # 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)" - $auditResult.FailureReason = if (-not $securityReportEnabled) { "Users cannot report security concerns in Teams due to one or more incorrect settings" } else { "N/A" } - $auditResult.Status = if ($securityReportEnabled) { "Pass" } else { "Fail" } - $auditResults += $auditResult + # Create and populate the CISAuditResult object + $params = @{ + Rec = "8.6.1" + Result = $securityReportEnabled + Status = if ($securityReportEnabled) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return auditResult + return $auditResult } } diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 3702ebd..43a8eef 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -1,21 +1,20 @@ function Test-RestrictCustomScripts { [CmdletBinding()] param ( + # Aligned # Define your parameters here if needed ) -#Limit All - begin { - # .TODO Test behavior in Prod - # Dot source the class script - $auditResults = @() + begin { + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { - # CIS 2.7 Ensure custom script execution is restricted on site collections - # Pass if DenyAddAndCustomizePages is set to true (Enabled). Fail otherwise. + # 7.3.4 (L1) Ensure custom script execution is restricted on site collections - # Get all site collections and select necessary properties + # 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') @@ -29,42 +28,34 @@ function Test-RestrictCustomScripts { "$($_.Title) ($($_.Url)): Custom Script Allowed" } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "2.7" - $auditResult.CISDescription = "Allowlist Authorized Scripts" - $auditResult.Rec = "7.3.4" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure custom script execution is restricted on site collections" - $auditResult.Result = $complianceResult - $auditResult.Details = if (-not $complianceResult) { - $nonCompliantSiteDetails -join "; " - } else { - "All site collections have custom script execution restricted" - } - $auditResult.FailureReason = if (-not $complianceResult) { + # Prepare failure reasons and details based on compliance + $failureReasons = if (-not $complianceResult) { "The following site collections allow custom script execution: " + ($nonCompliantSiteDetails -join "; ") - } else { + } + else { "N/A" } - $auditResult.Status = if ($complianceResult) { - "Pass" - } else { - "Fail" + + $details = if ($complianceResult) { + "All site collections have custom script execution restricted" + } + else { + $nonCompliantSiteDetails -join "; " } - $auditResults += $auditResult + # 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 { - # Return auditResults - return $auditResults + # Return auditResult + return $auditResult } } diff --git a/source/tests/Test-RestrictExternalSharing.ps1 b/source/tests/Test-RestrictExternalSharing.ps1 index 7d7a47c..f1b0568 100644 --- a/source/tests/Test-RestrictExternalSharing.ps1 +++ b/source/tests/Test-RestrictExternalSharing.ps1 @@ -1,37 +1,42 @@ function Test-RestrictExternalSharing { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 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') - # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" + # 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" + } - $auditResult.Rec = "7.2.3" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure external content sharing is restricted" + $details = "SharingCapability: $($SPOTenantSharingCapability.SharingCapability)" - $auditResult.Result = $isRestricted - $auditResult.Details = "SharingCapability: $($SPOTenantSharingCapability.SharingCapability)" - $auditResult.FailureReason = if (-not $isRestricted) { "External content sharing is not adequately restricted. Current setting: $($SPOTenantSharingCapability.SharingCapability)" } else { "N/A" } - $auditResult.Status = if ($isRestricted) { "Pass" } else { "Fail" } + # Create and populate the CISAuditResult object + $params = @{ + Rec = "7.2.3" + Result = $isRestricted + Status = if ($isRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-RestrictOutlookAddins.ps1 b/source/tests/Test-RestrictOutlookAddins.ps1 index be1e635..4438b50 100644 --- a/source/tests/Test-RestrictOutlookAddins.ps1 +++ b/source/tests/Test-RestrictOutlookAddins.ps1 @@ -1,20 +1,20 @@ function Test-RestrictOutlookAddins { [CmdletBinding()] param ( + # Aligned # Parameters could include credentials or other necessary data ) begin { + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 # Initialization code - - $auditResult = [CISAuditResult]::new() $customPolicyFailures = @() $defaultPolicyFailureDetails = @() $relevantRoles = @('My Custom Apps', 'My Marketplace Apps', 'My ReadWriteMailbox Apps') } process { - # Main functionality # 6.3.1 (L2) Ensure users installing Outlook add-ins is not allowed # Check all mailboxes for custom policies with unallowed add-ins @@ -38,24 +38,11 @@ function Test-RestrictOutlookAddins { if ($defaultPolicyRoles) { $defaultPolicyFailureDetails = $defaultPolicyRoles } - } - - end { - # Prepare result object - $auditResult.Rec = "6.3.1" - $auditResult.CISControl = "9.4" - $auditResult.CISDescription = "Restrict Unnecessary or Unauthorized Browser and Email Client Extensions" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure users installing Outlook add-ins is not allowed" + # Prepare result details string $detailsString = "" if ($customPolicyFailures) { $detailsString += "Custom Policy Failures: | " - # Use pipes or tabs here instead of newlines $detailsString += ($customPolicyFailures -join " | ") } else { @@ -70,20 +57,22 @@ function Test-RestrictOutlookAddins { $detailsString += "Compliant" } - if ($customPolicyFailures -or $defaultPolicyFailureDetails) { - $auditResult.Result = $false - $auditResult.Status = "Fail" - $auditResult.Details = $detailsString - $auditResult.FailureReason = "Unauthorized Outlook add-ins found in custom or default policies." - } - else { - $auditResult.Result = $true - $auditResult.Status = "Pass" - $auditResult.Details = "No unauthorized Outlook add-ins found in custom or default policies." - $auditResult.FailureReason = "N/A" - } + # Determine result based on findings + $isCompliant = -not ($customPolicyFailures -or $defaultPolicyFailureDetails) - # Return auditResult + # 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." } + } + $auditResult = Initialize-CISAuditResult @params + } + + end { + # Return the audit result return $auditResult } -} \ No newline at end of file +} diff --git a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 index 1aaf0d4..8400d72 100644 --- a/source/tests/Test-RestrictStorageProvidersOutlook.ps1 +++ b/source/tests/Test-RestrictStorageProvidersOutlook.ps1 @@ -1,48 +1,56 @@ function Test-RestrictStorageProvidersOutlook { [CmdletBinding()] param ( + # Aligned # Parameters can be added here if needed ) begin { - # Dot source the class script - - $auditResult = [CISAuditResult]::new() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 6.5.3 (L2) Ensure additional storage providers are restricted in Outlook on the web - $owaPolicies = Get-OwaMailboxPolicy - $allPoliciesRestricted = $owaPolicies | ForEach-Object { $_.AdditionalStorageProvidersAvailable } | ForEach-Object { -not $_ } - # Create an instance of CISAuditResult and populate it - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" - $auditResult.Rec = "6.5.3" - $auditResult.ELevel = "E3" # Based on your environment - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure additional storage providers are restricted in Outlook on the web" - $auditResult.Result = $allPoliciesRestricted - $auditResult.Details = if($allPoliciesRestricted) { - "All OwaMailbox policies restrict AdditionalStorageProvidersAvailable" - } else { - $nonCompliantPolicies = $owaPolicies | Where-Object { $_.AdditionalStorageProvidersAvailable } | Select-Object -ExpandProperty Name - "Non-compliant OwaMailbox policies: $($nonCompliantPolicies -join ', ')" + # Retrieve all OwaMailbox policies + $owaPolicies = Get-OwaMailboxPolicy + $nonCompliantPolicies = $owaPolicies | Where-Object { $_.AdditionalStorageProvidersAvailable } + + # Determine compliance + $allPoliciesRestricted = $nonCompliantPolicies.Count -eq 0 + + # Prepare failure reasons and details based on compliance + $failureReasons = if ($allPoliciesRestricted) { + "N/A" } - $auditResult.FailureReason = if(-not $allPoliciesRestricted) { "One or more OwaMailbox policies allow AdditionalStorageProvidersAvailable." } else { "N/A" } - $auditResult.Status = if($allPoliciesRestricted) { "Pass" } else { "Fail" } + 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 = "6.5.3" + Result = $allPoliciesRestricted + Status = if ($allPoliciesRestricted) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResult + # Return the audit result return $auditResult } } - # Additional helper functions (if any) - diff --git a/source/tests/Test-RestrictTenantCreation.ps1 b/source/tests/Test-RestrictTenantCreation.ps1 index 887c927..96bfb0f 100644 --- a/source/tests/Test-RestrictTenantCreation.ps1 +++ b/source/tests/Test-RestrictTenantCreation.ps1 @@ -1,43 +1,48 @@ function Test-RestrictTenantCreation { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - # Dot source the class script - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { # 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes' - # Pass if AllowedToCreateTenants is False. Fail otherwise. + + # Retrieve the tenant creation policy $tenantCreationPolicy = (Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions | Select-Object AllowedToCreateTenants $tenantCreationResult = -not $tenantCreationPolicy.AllowedToCreateTenants - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($tenantCreationResult) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "5.1.2.3" - $auditResult.RecDescription = "Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.Result = $tenantCreationResult - $auditResult.Details = "AllowedToCreateTenants: $($tenantCreationPolicy.AllowedToCreateTenants)" - $auditResult.FailureReason = if (-not $tenantCreationResult) { "Non-admin users can create tenants" } else { "N/A" } + # Prepare failure reasons and details based on compliance + $failureReasons = if ($tenantCreationResult) { + "N/A" + } + else { + "Non-admin users can create tenants" + } - $auditResults += $auditResult + $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 + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } + +# Additional helper functions (if any) diff --git a/source/tests/Test-SafeAttachmentsPolicy.ps1 b/source/tests/Test-SafeAttachmentsPolicy.ps1 index 588c932..48597ce 100644 --- a/source/tests/Test-SafeAttachmentsPolicy.ps1 +++ b/source/tests/Test-SafeAttachmentsPolicy.ps1 @@ -1,49 +1,53 @@ function Test-SafeAttachmentsPolicy { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { + # 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 } - # If there are any enabled policies, the result is Pass. If not, it's Fail. - $result = $safeAttachmentPolicies -ne $null -and $safeAttachmentPolicies.Count -gt 0 + # 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 { + } + else { "No Safe Attachments Policies are enabled." } - $failureReason = if ($result) { "N/A" } else { "Safe Attachments policy is not enabled." } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($result) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E5" - $auditResult.ProfileLevel = "L2" - $auditResult.Rec = "2.1.4" - $auditResult.RecDescription = "Ensure Safe Attachments policy is enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "9.7" - $auditResult.CISDescription = "Deploy and Maintain Email Server Anti-Malware Protections" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $true - $auditResult.Result = $result - $auditResult.Details = $details - $auditResult.FailureReason = $failureReason + $failureReasons = if ($result) { + "N/A" + } + else { + "Safe Attachments policy is not enabled." + } - $auditResults += $auditResult + # Create and populate the CISAuditResult object + $params = @{ + Rec = "2.1.4" + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } + +# Additional helper functions (if any) diff --git a/source/tests/Test-SafeAttachmentsTeams.ps1 b/source/tests/Test-SafeAttachmentsTeams.ps1 index 1647681..a1cb453 100644 --- a/source/tests/Test-SafeAttachmentsTeams.ps1 +++ b/source/tests/Test-SafeAttachmentsTeams.ps1 @@ -1,16 +1,19 @@ function Test-SafeAttachmentsTeams { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { - # Requires E5 license + # 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 @@ -25,33 +28,33 @@ function Test-SafeAttachmentsTeams { $result = $null -ne $atpPolicyResult $details = if ($result) { "ATP for SharePoint, OneDrive, and Teams is enabled with correct settings." - } else { + } + else { "ATP for SharePoint, OneDrive, and Teams is not enabled with correct settings." } - $failureReason = if ($result) { "N/A" } else { "ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured." } - # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($result) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E5" - $auditResult.ProfileLevel = "L2" - $auditResult.Rec = "2.1.5" - $auditResult.RecDescription = "Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "9.7, 10.1" - $auditResult.CISDescription = "Deploy and Maintain Email Server Anti-Malware Protections, Deploy and Maintain Anti-Malware Software" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $result - $auditResult.Details = $details - $auditResult.FailureReason = $failureReason + $failureReasons = if ($result) { + "N/A" + } + else { + "ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured." + } - $auditResults += $auditResult + # Create and populate the CISAuditResult object + $params = @{ + Rec = "2.1.5" + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } + +# Additional helper functions (if any) diff --git a/source/tests/Test-SafeLinksOfficeApps.ps1 b/source/tests/Test-SafeLinksOfficeApps.ps1 index 22bec97..46ee852 100644 --- a/source/tests/Test-SafeLinksOfficeApps.ps1 +++ b/source/tests/Test-SafeLinksOfficeApps.ps1 @@ -1,16 +1,19 @@ function Test-SafeLinksOfficeApps { [CmdletBinding()] param ( + # Aligned # Define your parameters here if needed ) begin { - # Initialization code - - $auditResults = @() + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed } process { + # 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled + # Retrieve all Safe Links policies $policies = Get-SafeLinksPolicy @@ -42,29 +45,21 @@ function Test-SafeLinksOfficeApps { # 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 the audit result object - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($result) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E5" - $auditResult.ProfileLevel = "L2" - $auditResult.Rec = "2.1.1" - $auditResult.RecDescription = "Ensure Safe Links for Office Applications is Enabled" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "10.1" - $auditResult.CISDescription = "Deploy and Maintain Anti-Malware Software" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $result - $auditResult.Details = $details - $auditResult.FailureReason = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" } - - $auditResults += $auditResult + # Create and populate the CISAuditResult object + $params = @{ + Rec = "2.1.1" + Result = $result + Status = if ($result) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return the audit result + return $auditResult } } diff --git a/source/tests/Test-SharePointAADB2B.ps1 b/source/tests/Test-SharePointAADB2B.ps1 index 2a93edb..a9af0c4 100644 --- a/source/tests/Test-SharePointAADB2B.ps1 +++ b/source/tests/Test-SharePointAADB2B.ps1 @@ -1,11 +1,14 @@ function Test-SharePointAADB2B { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $auditResult = [CISAuditResult]::new() } @@ -15,22 +18,14 @@ function Test-SharePointAADB2B { $SPOTenantAzureADB2B = Get-SPOTenant | Select-Object EnableAzureADB2BIntegration # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" - $auditResult.CISDescription = "Explicitly Not Mapped" - - $auditResult.Rec = "7.2.2" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.IG1 = $false - $auditResult.IG2 = $false - $auditResult.IG3 = $false - $auditResult.RecDescription = "Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled" - - $auditResult.Result = $SPOTenantAzureADB2B.EnableAzureADB2BIntegration - $auditResult.Details = "EnableAzureADB2BIntegration: $($SPOTenantAzureADB2B.EnableAzureADB2BIntegration)" - $auditResult.FailureReason = if (-not $SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Azure AD B2B integration is not enabled" } else { "N/A" } - $auditResult.Status = if ($SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Pass" } else { "Fail" } + $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" } + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SharePointExternalSharingDomains.ps1 b/source/tests/Test-SharePointExternalSharingDomains.ps1 index 5e30c94..25f4213 100644 --- a/source/tests/Test-SharePointExternalSharingDomains.ps1 +++ b/source/tests/Test-SharePointExternalSharingDomains.ps1 @@ -1,11 +1,14 @@ function Test-SharePointExternalSharingDomains { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $auditResult = [CISAuditResult]::new() } @@ -16,22 +19,14 @@ function Test-SharePointExternalSharingDomains { $isDomainRestrictionConfigured = $SPOTenant.SharingDomainRestrictionMode -eq 'AllowList' # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" - - $auditResult.Rec = "7.2.6" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure SharePoint external sharing is managed through domain whitelist/blacklists" - - $auditResult.Result = $isDomainRestrictionConfigured - $auditResult.Details = "SharingDomainRestrictionMode: $($SPOTenant.SharingDomainRestrictionMode); SharingAllowedDomainList: $($SPOTenant.SharingAllowedDomainList)" - $auditResult.FailureReason = if (-not $isDomainRestrictionConfigured) { "Domain restrictions for SharePoint external sharing are not configured to 'AllowList'. Current setting: $($SPOTenant.SharingDomainRestrictionMode)" } else { "N/A" } - $auditResult.Status = if ($isDomainRestrictionConfigured) { "Pass" } else { "Fail" } + $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" } + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SharePointGuestsItemSharing.ps1 b/source/tests/Test-SharePointGuestsItemSharing.ps1 index ac50ac6..6f35325 100644 --- a/source/tests/Test-SharePointGuestsItemSharing.ps1 +++ b/source/tests/Test-SharePointGuestsItemSharing.ps1 @@ -1,11 +1,14 @@ function Test-SharePointGuestsItemSharing { [CmdletBinding()] param ( + # Aligned # Define your parameters here ) begin { - # Initialization code + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed $auditResult = [CISAuditResult]::new() } @@ -16,22 +19,14 @@ function Test-SharePointGuestsItemSharing { $isGuestResharingPrevented = $SPOTenant.PreventExternalUsersFromResharing # Populate the auditResult object with the required properties - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" - - $auditResult.Rec = "7.2.5" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $true - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.RecDescription = "Ensure that SharePoint guest users cannot share items they don't own" - - $auditResult.Result = $isGuestResharingPrevented - $auditResult.Details = "PreventExternalUsersFromResharing: $isGuestResharingPrevented" - $auditResult.FailureReason = if (-not $isGuestResharingPrevented) { "Guest users can reshare items they don't own." } else { "N/A" } - $auditResult.Status = if ($isGuestResharingPrevented) { "Pass" } else { "Fail" } + $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" } + } + $auditResult = Initialize-CISAuditResult @params } end { diff --git a/source/tests/Test-SpamPolicyAdminNotify.ps1 b/source/tests/Test-SpamPolicyAdminNotify.ps1 index ebe2d81..05be9aa 100644 --- a/source/tests/Test-SpamPolicyAdminNotify.ps1 +++ b/source/tests/Test-SpamPolicyAdminNotify.ps1 @@ -1,16 +1,20 @@ function Test-SpamPolicyAdminNotify { [CmdletBinding()] param ( + # Aligned # Parameters can be added if needed ) begin { + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed - $auditResults = @() + $auditResult = [CISAuditResult]::new() } process { - # 2.1.6 Ensure Exchange Online Spam Policies are set to notify administrators + # 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 } @@ -30,29 +34,18 @@ function Test-SpamPolicyAdminNotify { } # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.Status = if ($areSettingsEnabled) { "Pass" } else { "Fail" } - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L1" - $auditResult.Rec = "2.1.6" - $auditResult.RecDescription = "Ensure Exchange Online Spam Policies are set to notify administrators" - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "17.5" - $auditResult.CISDescription = "Assign Key Roles and Responsibilities" - $auditResult.IG1 = $false - $auditResult.IG2 = $true - $auditResult.IG3 = $true - $auditResult.Result = $areSettingsEnabled - $auditResult.Details = if ($areSettingsEnabled) { "Both BccSuspiciousOutboundMail and NotifyOutboundSpam are enabled." } else { $failureDetails -join ' ' } - $auditResult.FailureReason = if (-not $areSettingsEnabled) { "One or both spam policies are not set to notify administrators." } else { "N/A" } - - $auditResults += $auditResult + $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" } + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return auditResult + return $auditResult } } - - diff --git a/source/tests/Test-TeamsExternalAccess.ps1 b/source/tests/Test-TeamsExternalAccess.ps1 index ef4d67d..8b0cad2 100644 --- a/source/tests/Test-TeamsExternalAccess.ps1 +++ b/source/tests/Test-TeamsExternalAccess.ps1 @@ -1,13 +1,16 @@ function Test-TeamsExternalAccess { [CmdletBinding()] param ( + # Aligned # Parameters can be defined here if needed ) begin { - # Dot source the class script + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed - $auditResults = @() + $auditResult = [CISAuditResult]::new() } process { @@ -26,27 +29,18 @@ function Test-TeamsExternalAccess { $isCompliant = -not $externalAccessConfig.AllowTeamsConsumer -and -not $externalAccessConfig.AllowPublicUsers -and (-not $externalAccessConfig.AllowFederatedUsers -or $allowedDomainsLimited) # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "0.0" # The control is Explicitly Not Mapped as per the image provided - $auditResult.CISDescription = "Explicitly Not Mapped" - $auditResult.Rec = "8.2.1" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $false # Set based on the CIS Controls image - $auditResult.IG2 = $false # Set based on the CIS Controls image - $auditResult.IG3 = $false # Set based on the CIS Controls image - $auditResult.RecDescription = "Ensure 'external access' is restricted in the Teams admin center" - $auditResult.Result = $isCompliant - $auditResult.Details = "AllowTeamsConsumer: $($externalAccessConfig.AllowTeamsConsumer); AllowPublicUsers: $($externalAccessConfig.AllowPublicUsers); AllowFederatedUsers: $($externalAccessConfig.AllowFederatedUsers); AllowedDomains limited: $allowedDomainsLimited" - $auditResult.FailureReason = if (-not $isCompliant) { "One or more external access configurations are not compliant." } else { "N/A" } - $auditResult.Status = if ($isCompliant) { "Pass" } else { "Fail" } - - $auditResults += $auditResult + $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" } + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return auditResult + return $auditResult } } diff --git a/source/tests/Test-TeamsExternalFileSharing.ps1 b/source/tests/Test-TeamsExternalFileSharing.ps1 index 0c7d5ba..fd4e653 100644 --- a/source/tests/Test-TeamsExternalFileSharing.ps1 +++ b/source/tests/Test-TeamsExternalFileSharing.ps1 @@ -1,13 +1,16 @@ function Test-TeamsExternalFileSharing { [CmdletBinding()] param ( + # Aligned # Parameters can be added here if needed ) begin { - # Dot source the class script + # Dot source the class script if necessary + #. .\source\Classes\CISAuditResult.ps1 + # Initialization code, if needed - $auditResults = @() + $auditResult = [CISAuditResult]::new() } process { @@ -30,27 +33,18 @@ function Test-TeamsExternalFileSharing { } # Create an instance of CISAuditResult and populate it - $auditResult = [CISAuditResult]::new() - $auditResult.CISControlVer = "v8" - $auditResult.CISControl = "3.3" - $auditResult.CISDescription = "Configure Data Access Control Lists" - $auditResult.Rec = "8.1.1" - $auditResult.ELevel = "E3" - $auditResult.ProfileLevel = "L2" - $auditResult.IG1 = $true # Set based on the benchmark - $auditResult.IG2 = $true # Set based on the benchmark - $auditResult.IG3 = $true # Set based on the benchmark - $auditResult.RecDescription = "Ensure external file sharing in Teams is enabled for only approved cloud storage services" - $auditResult.Result = $isCompliant - $auditResult.Details = if (-not $isCompliant) { "Non-approved providers enabled: $($nonCompliantProviders -join ', ')" } else { "All cloud storage services are approved providers" } - $auditResult.FailureReason = if (-not $isCompliant) { "The following non-approved providers are enabled: $($nonCompliantProviders -join ', ')" } else { "N/A" } - $auditResult.Status = if ($isCompliant) { "Pass" } else { "Fail" } - - $auditResults += $auditResult + $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" } + } + $auditResult = Initialize-CISAuditResult @params } end { - # Return auditResults - return $auditResults + # Return auditResult + return $auditResult } -} \ No newline at end of file +} diff --git a/tests/Unit/Private/Initialize-CISAuditResult.tests.ps1 b/tests/Unit/Private/Initialize-CISAuditResult.tests.ps1 new file mode 100644 index 0000000..4a2aa69 --- /dev/null +++ b/tests/Unit/Private/Initialize-CISAuditResult.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' + } + } + } +} +