diff --git a/source/Private/Get-MostCommonWord.ps1 b/source/Private/Get-MostCommonWord.ps1 new file mode 100644 index 0000000..b626b5e --- /dev/null +++ b/source/Private/Get-MostCommonWord.ps1 @@ -0,0 +1,22 @@ +function Get-MostCommonWord { + param ( + [Parameter(Mandatory = $true)] + [string[]]$InputStrings + ) + + # Combine all strings into one large string + $allText = $InputStrings -join ' ' + + # Split the large string into words + $words = $allText -split '\s+' + + # Group words and count occurrences + $wordGroups = $words | Group-Object | Sort-Object Count -Descending + + # Return the most common word if it occurs at least 3 times + if ($wordGroups.Count -gt 0 -and $wordGroups[0].Count -ge 3) { + return $wordGroups[0].Name + } else { + return $null + } +} \ No newline at end of file diff --git a/source/tests/Test-RestrictCustomScripts.ps1 b/source/tests/Test-RestrictCustomScripts.ps1 index e1ad809..5dbd411 100644 --- a/source/tests/Test-RestrictCustomScripts.ps1 +++ b/source/tests/Test-RestrictCustomScripts.ps1 @@ -20,29 +20,43 @@ function Test-RestrictCustomScripts { # Retrieve all site collections and select necessary properties $SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages - # Replace 'sharepoint.com' with '' + # Replace 'sharepoint.com' with '' $processedUrls = $SPOSitesCustomScript | ForEach-Object { - $_.Url = $_.Url -replace 'sharepoint\.com', '' + $_.Url = $_.Url -replace 'sharepoint\.com', '' $_ } - # Extract hostnames and find the most used one - $hostnames = $processedUrls.Url | ForEach-Object { $_ -match '^https://([^\.]+)\.' | Out-Null; $matches[1] } - $mostUsedHostname = $hostnames | Group-Object | Sort-Object Count -Descending | Select-Object -First 1 -ExpandProperty Name + # Find sites where custom scripts are allowed + $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } + + # Extract hostnames from allowed sites + Write-Verbose "Extracting hostnames from URLs..." + $hostnames = $customScriptAllowedSites.Url | ForEach-Object { + if ($_ -match '^https://([^\.]+)\.') { + $matches[1] + } + } + Write-Verbose "Extracted hostnames: $($hostnames -join ', ')" + + # Find the most used hostname using the Get-MostCommonWord function + $mostUsedHostname = Get-MostCommonWord -InputStrings $hostnames + Write-Verbose "Most used hostname: $mostUsedHostname" # Compliance is true if no sites allow custom scripts - $customScriptAllowedSites = $processedUrls | Where-Object { $_.DenyAddAndCustomizePages -ne 'Enabled' } $complianceResult = $customScriptAllowedSites.Count -eq 0 # Gather details for non-compliant sites (where custom scripts are allowed) $nonCompliantSiteDetails = $customScriptAllowedSites | ForEach-Object { - $url = $_.Url -replace [regex]::Escape($mostUsedHostname), "" - "$(if ($_.Title) {$_.Title} else {"NoTitle"})|$url|$true" + $url = $_.Url + if ($null -ne $mostUsedHostname -and $url -match "^https://$mostUsedHostname\.") { + $url = $url -replace "^https://$mostUsedHostname\.", "https://." + } + "$(if ($_.Title) {$_.Title} else {"NoTitle"})|$url" } # Prepare failure reasons and details based on compliance $failureReasons = if (-not $complianceResult) { - "Title|Url|CustomScriptAllowed`n" + ($nonCompliantSiteDetails -join "`n") + "Some site collections are not restricting custom script execution. Review Details property for sites that are not aligned with the benchmark." } else { "N/A" @@ -52,16 +66,16 @@ function Test-RestrictCustomScripts { "All site collections have custom script execution restricted" } else { - "Some site collections are not restricting custom script execution. Review FailureReason property for sites that are not aligned with the benchmark." + "Title|Url`n" + ($nonCompliantSiteDetails -join "`n") } # Create and populate the CISAuditResult object $params = @{ - Rec = $recnum - Result = $complianceResult - Status = if ($complianceResult) { "Pass" } else { "Fail" } - Details = $details - FailureReason = $failureReasons + Rec = $recnum + Result = $complianceResult + Status = if ($complianceResult) { "Pass" } else { "Fail" } + Details = $details + FailureReason = $failureReasons } $auditResult = Initialize-CISAuditResult @params } @@ -80,6 +94,15 @@ function Test-RestrictCustomScripts { } end { + # Measure the character count of the details + $verbosePreference = 'Continue' + $detailsLength = $details.Length + Write-Verbose "Character count of the details: $detailsLength" + + if ($detailsLength -gt 32767) { + Write-Verbose "Warning: The character count exceeds the limit for Excel cells." + } + $verbosePreference = 'SilentlyContinue' # Return auditResult return $auditResult }