diff --git a/source/Private/Get-CISSpoOutput.ps1 b/source/Private/Get-CISSpoOutput.ps1 index cd94403..99362cd 100644 --- a/source/Private/Get-CISSpoOutput.ps1 +++ b/source/Private/Get-CISSpoOutput.ps1 @@ -101,18 +101,39 @@ function Get-CISSpoOutput { '7.2.6' { # Test-SharePointExternalSharingDomains.ps1 # 7.2.6 (L2) Ensure SharePoint external sharing is managed through domain whitelist/blacklists + # Add Authorized Domains? + # $SPOTenant Mock Object + <# + $SPOTenant = [PSCustomObject]@{ + SharingDomainRestrictionMode = "AllowList" + SharingAllowedDomainList = "domain1.com", "domain2.com" + } + #> $SPOTenant = Get-SPOTenant | Select-Object SharingDomainRestrictionMode, SharingAllowedDomainList return $SPOTenant } '7.2.7' { # Test-LinkSharingRestrictions.ps1 # Retrieve link sharing configuration for SharePoint and OneDrive + # $SPOTenantLinkSharing Mock Object + <# + $$SPOTenantLinkSharing = [PSCustomObject]@{ + DefaultSharingLinkType = "Direct" + } + #> $SPOTenantLinkSharing = Get-SPOTenant | Select-Object DefaultSharingLinkType return $SPOTenantLinkSharing } '7.2.9' { # Test-GuestAccessExpiration.ps1 # Retrieve SharePoint tenant settings related to guest access expiration + # $SPOTenantGuestAccess Mock Object + <# + $SPOTenantGuestAccess = [PSCustomObject]@{ + ExternalUserExpirationRequired = "$false" + ExternalUserExpireInDays = "60" + } + #> $SPOTenantGuestAccess = Get-SPOTenant | Select-Object ExternalUserExpirationRequired, ExternalUserExpireInDays return $SPOTenantGuestAccess } @@ -120,24 +141,53 @@ function Get-CISSpoOutput { # Test-ReauthWithCode.ps1 # 7.2.10 (L1) Ensure reauthentication with verification code is restricted # Retrieve reauthentication settings for SharePoint Online + # $SPOTenantReauthentication Mock Object + <# + $SPOTenantReauthentication = [PSCustomObject]@{ + EmailAttestationRequired = "$false" + EmailAttestationReAuthDays = "30" + } + #> $SPOTenantReauthentication = Get-SPOTenant | Select-Object EmailAttestationRequired, EmailAttestationReAuthDays return $SPOTenantReauthentication } '7.3.1' { # Test-DisallowInfectedFilesDownload.ps1 # Retrieve the SharePoint tenant configuration + # $SPOTenantDisallowInfectedFileDownload Mock Object + <# + $SPOTenantDisallowInfectedFileDownload = [PSCustomObject]@{ + DisallowInfectedFileDownload = $false + } + #> $SPOTenantDisallowInfectedFileDownload = Get-SPOTenant | Select-Object DisallowInfectedFileDownload return $SPOTenantDisallowInfectedFileDownload } '7.3.2' { # Test-OneDriveSyncRestrictions.ps1 # Retrieve OneDrive sync client restriction settings + # Add isHybrid paramter? + # $SPOTenantSyncClientRestriction Mock Object + <# + $SPOTenantSyncClientRestriction = [PSCustomObject]@{ + TenantRestrictionEnabled = $true + AllowedDomainList = "786548DD-877B-4760-A749-6B1EFBC1190A", "877564FF-877B-4760-A749-6B1EFBC1190A" + } + #> $SPOTenantSyncClientRestriction = Get-SPOTenantSyncClientRestriction | Select-Object TenantRestrictionEnabled, AllowedDomainList return $SPOTenantSyncClientRestriction } '7.3.4' { # Test-RestrictCustomScripts.ps1 # Retrieve all site collections and select necessary properties + # $SPOSitesCustomScript Mock Object + <# + $SPOSitesCustomScript = [PSCustomObject]@{ + Title = "Site Collection 1" + Url = "https://contoso.sharepoint.com/sites/site1" + DenyAddAndCustomizePages = "Enabled" + } + #> $SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages return $SPOSitesCustomScript } diff --git a/source/tests/Test-DisallowInfectedFilesDownload.ps1 b/source/tests/Test-DisallowInfectedFilesDownload.ps1 index 851c90b..8afd659 100644 --- a/source/tests/Test-DisallowInfectedFilesDownload.ps1 +++ b/source/tests/Test-DisallowInfectedFilesDownload.ps1 @@ -5,17 +5,14 @@ function Test-DisallowInfectedFilesDownload { # Aligned # Define your parameters here if needed ) - begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 - # Initialization code, if needed $recnum = "7.3.1" + Write-Verbose "Running Test-DisallowInfectedFilesDownload for $recnum..." } - process { - try { # 7.3.1 (L2) Ensure Office 365 SharePoint infected files are disallowed for download # @@ -32,28 +29,30 @@ function Test-DisallowInfectedFilesDownload { # - Condition A: The `DisallowInfectedFileDownload` setting is not set to `True`. # - Condition B: The setting does not prevent users from downloading infected files. # - Condition C: Verification using the PowerShell command indicates that the setting is incorrectly configured. - # Retrieve the SharePoint tenant configuration + # $SPOTenantDisallowInfectedFileDownload Mock Object + <# + $SPOTenantDisallowInfectedFileDownload = [PSCustomObject]@{ + DisallowInfectedFileDownload = $false + } + #> $SPOTenantDisallowInfectedFileDownload = Get-CISSpoOutput -Rec $recnum - # Condition A: The `DisallowInfectedFileDownload` setting is set to `True` $isDisallowInfectedFileDownloadEnabled = $SPOTenantDisallowInfectedFileDownload.DisallowInfectedFileDownload - # Prepare failure reasons and details based on compliance $failureReasons = if (-not $isDisallowInfectedFileDownloadEnabled) { - "Downloading infected files is not disallowed." # Condition B: The setting does not prevent users from downloading infected files + "Downloading infected files is not disallowed. To ensure infected files cannot be downloaded, use the following command:`n" + ` # Condition B: The setting does not prevent users from downloading infected files + "Set-SPOTenant -DisallowInfectedFileDownload `$true" } else { "N/A" } - $details = if ($isDisallowInfectedFileDownloadEnabled) { "DisallowInfectedFileDownload: True" # Condition C: Verification confirms the setting is correctly configured } else { "DisallowInfectedFileDownload: False" # Condition C: Verification indicates the setting is incorrectly configured } - # Create and populate the CISAuditResult object $params = @{ Rec = $recnum @@ -69,9 +68,8 @@ function Test-DisallowInfectedFilesDownload { $auditResult = Get-TestError -LastError $LastError -recnum $recnum } } - end { # Return the audit result return $auditResult } -} +} \ No newline at end of file diff --git a/source/tests/Test-GuestAccessExpiration.ps1 b/source/tests/Test-GuestAccessExpiration.ps1 index 92d40a0..666ad61 100644 --- a/source/tests/Test-GuestAccessExpiration.ps1 +++ b/source/tests/Test-GuestAccessExpiration.ps1 @@ -5,17 +5,14 @@ function Test-GuestAccessExpiration { # Aligned # Define your parameters here if needed ) - begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 - # Initialization code, if needed $recnum = "7.2.9" + Write-Verbose "Running Test-GuestAccessExpiration for $recnum..." } - process { - try { # 7.2.9 (L1) Ensure guest access to a site or OneDrive will expire automatically # @@ -32,21 +29,25 @@ function Test-GuestAccessExpiration { # - Condition A: The ExternalUserExpirationRequired setting in SharePoint is not set to True. # - Condition B: The ExternalUserExpireInDays setting in SharePoint is configured to more than 30 days. # - Condition C: Verification using the SharePoint Admin Center indicates that guest access is not set to expire automatically after the specified number of days. - # Retrieve SharePoint tenant settings related to guest access expiration + # $SPOTenantGuestAccess Mock Object + <# + $SPOTenantGuestAccess = [PSCustomObject]@{ + ExternalUserExpirationRequired = "$false" + ExternalUserExpireInDays = "60" + } + #> $SPOTenantGuestAccess = Get-CISSpoOutput -Rec $recnum $isGuestAccessExpirationConfiguredCorrectly = $SPOTenantGuestAccess.ExternalUserExpirationRequired -and $SPOTenantGuestAccess.ExternalUserExpireInDays -le 30 - # 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." + "Guest access expiration is not configured to automatically expire within 30 days or less. To remediate this setting, use the Set-SPOTenant command:`n`n" + ` + "Set-SPOTenant -ExternalUserExpirationRequired `$true -ExternalUserExpireInDays 30" } else { "N/A" } - $details = "ExternalUserExpirationRequired: $($SPOTenantGuestAccess.ExternalUserExpirationRequired); ExternalUserExpireInDays: $($SPOTenantGuestAccess.ExternalUserExpireInDays)" - # Create and populate the CISAuditResult object $params = @{ Rec = $recnum @@ -62,7 +63,6 @@ function Test-GuestAccessExpiration { $auditResult = Get-TestError -LastError $LastError -recnum $recnum } } - end { # Return the audit result return $auditResult diff --git a/source/tests/Test-LinkSharingRestrictions.ps1 b/source/tests/Test-LinkSharingRestrictions.ps1 index 9816d51..08fdab0 100644 --- a/source/tests/Test-LinkSharingRestrictions.ps1 +++ b/source/tests/Test-LinkSharingRestrictions.ps1 @@ -6,14 +6,13 @@ function Test-LinkSharingRestrictions { # Define your parameters here # Test behavior in prod ) - begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed $recnum = "7.2.7" + Write-Verbose "Running Test-LinkSharingRestrictions for $recnum..." } - process { try { # 7.2.7 (L1) Ensure link sharing is restricted in SharePoint and OneDrive @@ -31,21 +30,24 @@ function Test-LinkSharingRestrictions { # - Condition A: The `DefaultSharingLinkType` setting in SharePoint and OneDrive is not set to `Direct`. # - Condition B: The setting `Choose the type of link that's selected by default when users share files and folders in SharePoint and OneDrive` is not set to `Specific people (only the people the user specifies)`. # - Condition C: Verification using the UI indicates that the link sharing settings are not configured as recommended. - # Retrieve link sharing configuration for SharePoint and OneDrive + # $SPOTenantLinkSharing Mock Object + <# + $$SPOTenantLinkSharing = [PSCustomObject]@{ + DefaultSharingLinkType = "Direct" + } + #> $SPOTenantLinkSharing = Get-CISSpoOutput -Rec $recnum $isLinkSharingRestricted = $SPOTenantLinkSharing.DefaultSharingLinkType -eq 'Direct' # Or 'SpecificPeople' as per the recommendation - # Prepare failure reasons and details based on compliance $failureReasons = if (-not $isLinkSharingRestricted) { - "Link sharing is not restricted to 'Specific people'. Current setting: $($SPOTenantLinkSharing.DefaultSharingLinkType)" + "Link sharing is not restricted to 'Specific people'. Current setting: $($SPOTenantLinkSharing.DefaultSharingLinkType). To remediate this setting, use the Set-SPOTenant command:`n`n" + ` + "Set-SPOTenant -DefaultSharingLinkType Direct" } else { "N/A" } - $details = "DefaultSharingLinkType: $($SPOTenantLinkSharing.DefaultSharingLinkType)" - # Create and populate the CISAuditResult object $params = @{ Rec = $recnum @@ -55,14 +57,12 @@ function Test-LinkSharingRestrictions { FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params - } catch { $LastError = $_ $auditResult = Get-TestError -LastError $LastError -recnum $recnum } } - end { # Return the audit result return $auditResult diff --git a/source/tests/Test-OneDriveSyncRestrictions.ps1 b/source/tests/Test-OneDriveSyncRestrictions.ps1 index f689d37..b78eeae 100644 --- a/source/tests/Test-OneDriveSyncRestrictions.ps1 +++ b/source/tests/Test-OneDriveSyncRestrictions.ps1 @@ -5,14 +5,13 @@ function Test-OneDriveSyncRestrictions { # Aligned # Define your parameters here ) - begin { # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed $recnum = "7.3.2" + Write-Verbose "Running Test-OneDriveSyncRestrictions for $recnum..." } - process { try { # 7.3.2 (L2) Ensure OneDrive sync is restricted for unmanaged devices @@ -30,20 +29,20 @@ function Test-OneDriveSyncRestrictions { # - Condition A: "Allow syncing only on computers joined to specific domains" is not enabled. # - Condition B: "TenantRestrictionEnabled" is set to False. # - Condition C: "AllowedDomainList" does not contain the trusted domain GUIDs from the on-premises environment. - # Retrieve OneDrive sync client restriction settings $SPOTenantSyncClientRestriction = Get-CISSpoOutput -Rec $recnum $isSyncRestricted = $SPOTenantSyncClientRestriction.TenantRestrictionEnabled -and $SPOTenantSyncClientRestriction.AllowedDomainList - # Condition A: Check if TenantRestrictionEnabled is True # Condition B: Ensure AllowedDomainList contains trusted domains GUIDs $failureReasons = if (-not $isSyncRestricted) { - "OneDrive sync is not restricted to managed devices. TenantRestrictionEnabled should be True and AllowedDomainList should contain trusted domains GUIDs." + "OneDrive sync is not restricted to managed devices. For hybrid devices, TenantRestrictionEnabled should be True and AllowedDomainList should contain trusted domains GUIDs.`n" + ` + "To remediate this setting, edit and use the Set-SPOTenantSyncClientRestriction command below:`n" + ` + "Set-SPOTenantSyncClientRestriction -TenantRestrictionEnabled `$true -AllowedDomainList `"`",`"`"`n`n" + ` + "Note: Utilize the -BlockMacSync:`$true parameter if you are not using conditional access to ensure Macs cannot sync." } else { "N/A" } - # Condition C: Prepare details based on whether sync is restricted $details = if ($isSyncRestricted) { "OneDrive sync is restricted for unmanaged devices." @@ -51,7 +50,6 @@ function Test-OneDriveSyncRestrictions { else { "TenantRestrictionEnabled: $($SPOTenantSyncClientRestriction.TenantRestrictionEnabled); AllowedDomainList: $($SPOTenantSyncClientRestriction.AllowedDomainList -join ', ')" } - # Create and populate the CISAuditResult object $params = @{ Rec = $recnum @@ -67,7 +65,6 @@ function Test-OneDriveSyncRestrictions { $auditResult = Get-TestError -LastError $LastError -recnum $recnum } } - end { # Return auditResult return $auditResult diff --git a/source/tests/Test-ReauthWithCode.ps1 b/source/tests/Test-ReauthWithCode.ps1 index 9e68202..1ec2bb0 100644 --- a/source/tests/Test-ReauthWithCode.ps1 +++ b/source/tests/Test-ReauthWithCode.ps1 @@ -5,7 +5,6 @@ function Test-ReauthWithCode { # Aligned # Define your parameters here ) - begin { <# Conditions for 7.2.10 (L1) Ensure reauthentication with verification code is restricted @@ -22,31 +21,34 @@ function Test-ReauthWithCode { # - Condition A: The `EmailAttestationRequired` property is set to `False`. # - Condition B: The `EmailAttestationReAuthDays` property is set to more than `15`. #> - # Dot source the class script if necessary #. .\source\Classes\CISAuditResult.ps1 # Initialization code, if needed $recnum = "7.2.10" + Write-Verbose "Running Test-ReauthWithCode for $recnum..." } - process { try { # 7.2.10 (L1) Ensure reauthentication with verification code is restricted - # Retrieve reauthentication settings for SharePoint Online + # $SPOTenantReauthentication Mock Object + <# + $SPOTenantReauthentication = [PSCustomObject]@{ + EmailAttestationRequired = "$false" + EmailAttestationReAuthDays = "30" + } + #> $SPOTenantReauthentication = Get-CISSpoOutput -Rec $recnum $isReauthenticationRestricted = $SPOTenantReauthentication.EmailAttestationRequired -and $SPOTenantReauthentication.EmailAttestationReAuthDays -le 15 - # Prepare failure reasons and details based on compliance $failureReasons = if (-not $isReauthenticationRestricted) { - "Reauthentication with verification code does not require reauthentication within 15 days or less." + "Reauthentication with verification code does not require reauthentication within 15 days or less. To remediate this setting, use the Set-SPOTenant command:`n" + ` + "Set-SPOTenant -EmailAttestationRequired `$true -EmailAttestationReAuthDays 15" } else { "N/A" } - $details = "EmailAttestationRequired: $($SPOTenantReauthentication.EmailAttestationRequired); EmailAttestationReAuthDays: $($SPOTenantReauthentication.EmailAttestationReAuthDays)" - # Create and populate the CISAuditResult object $params = @{ Rec = $recnum @@ -62,7 +64,6 @@ function Test-ReauthWithCode { $auditResult = Get-TestError -LastError $LastError -recnum $recnum } } - end { # Return auditResult return $auditResult diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index 88f1c75..b9f9cda 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -4,15 +4,13 @@ function Test-RestrictCustomScripts { param ( # Define your parameters here if needed ) - begin { # Dot source the class script if necessary # . .\source\Classes\CISAuditResult.ps1 - # Initialization code, if needed $recnum = "7.3.4" + Write-Verbose "Running Test-RestrictCustomScripts for $recnum..." } - process { try { # 7.3.4 (L1) Ensure custom script execution is restricted on site collections @@ -30,23 +28,27 @@ function Test-RestrictCustomScripts { # - Condition A: The `DenyAddAndCustomizePages` setting is not set to `Enabled` for any site collection. # - Condition B: The setting is not validated through PowerShell commands, indicating misconfiguration. # - Condition C: Verification using the SharePoint Admin Center indicates that the `DenyAddAndCustomizePages` setting is not enforced. - # Retrieve all site collections and select necessary properties + # $SPOSitesCustomScript Mock Object + <# + $SPOSitesCustomScript = [PSCustomObject]@{ + Title = "Site Collection 1" + Url = "https://contoso.sharepoint.com/sites/site1" + DenyAddAndCustomizePages = "Enabled" + } + #> $SPOSitesCustomScript = Get-CISSpoOutput -Rec $recnum - # Process URLs to replace 'sharepoint.com' with '' $processedUrls = $SPOSitesCustomScript | ForEach-Object { $_.Url = $_.Url -replace 'sharepoint\.com', '' $_ } - # Find sites where custom scripts are allowed $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } #$verbosePreference = 'Continue' # Check the total length of URLs $totalUrlLength = ($customScriptAllowedSites.Url -join '').Length Write-Verbose "Total length of URLs: $totalUrlLength" - # Extract hostnames from allowed sites if the total length exceeds the limit $mostUsedHostname = $null if ($totalUrlLength -gt 20000) { @@ -57,7 +59,6 @@ function Test-RestrictCustomScripts { } } Write-Verbose "Extracted hostnames: $($hostnames -join ', ')" - # Find the most used hostname using the Get-MostCommonWord function $mostUsedHostname = Get-MostCommonWord -InputStrings $hostnames Write-Verbose "Most used hostname: $mostUsedHostname" @@ -65,7 +66,6 @@ function Test-RestrictCustomScripts { #$verbosePreference = 'SilentlyContinue' # Compliance is true if no sites allow custom scripts $complianceResult = $customScriptAllowedSites.Count -eq 0 - # Gather details for non-compliant sites (where custom scripts are allowed) $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { $url = $_.Url @@ -74,32 +74,29 @@ function Test-RestrictCustomScripts { } "$(if ($_.Title) {$_.Title} else {"NoTitle"})|$url" } - # Prepare failure reasons and details based on compliance $failureReasons = if (-not $complianceResult) { - "Some site collections are not restricting custom script execution. Review Details property for sites that are not aligned with the benchmark." + "Some site collections are not restricting custom script execution. Review Details property for sites that are not aligned with the benchmark.`n" + ` + "To remediate this setting, use the following command:`n" + ` + "Set-SPOSite -Identity -DenyAddAndCustomizePages `$true" } else { "N/A" } - $details = if ($complianceResult) { "All site collections have custom script execution restricted" } else { "Title|Url`n" + ($nonCompliantSiteDetails -join "`n") } - # Convert details to PSObject and check length $detailsPSObject = $details | ConvertFrom-Csv -Delimiter '|' $detailsLength = ($detailsPSObject | ForEach-Object { $_.Url }).Length - if ($detailsLength -gt 32767) { # Create a preview of the first 10 results $preview = $detailsPSObject | Select-Object -First 10 | ForEach-Object { "$($_.Title)|$($_.Url)" } $details = "The output is too large. Here is a preview of the first 10 results:`n`n" + ($preview -join "`n") + "`n`nPlease run the test with the following commands to get the full details:`n`nGet-SPOSite -Limit All | Where-Object { `$.DenyAddAndCustomizePages -ne 'Enabled' } | Select-Object Title, Url" } - # Create and populate the CISAuditResult object $params = @{ Rec = $recnum