Public/Test-PurviewCompliance.ps1
function Test-PurviewCompliance { <# .SYNOPSIS Runs compliance assessment against collected Purview configuration data. .DESCRIPTION Evaluates Microsoft Purview configuration against specified control books and generates compliance reports. .PARAMETER OptimizedReportPath Path to the OptimizedReport JSON file containing configuration data .PARAMETER Configuration Control book configuration to use for assessment (default: PSPF) .PARAMETER OutputPath Output directory for generated reports .PARAMETER GenerateExcel Generate Excel reports in addition to CSV files .EXAMPLE Test-PurviewCompliance -OptimizedReportPath "C:\Reports\OptimizedReport.json" -Configuration "PSPF" -GenerateExcel Runs PSPF compliance assessment and generates Excel reports. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$OptimizedReportPath, [Parameter(Mandatory = $false)] [string]$Configuration = 'PSPF', [Parameter(Mandatory = $false)] [string]$OutputPath = (Join-Path $env:USERPROFILE "PurviewConfigAnalyser\Output"), [Parameter(Mandatory = $false)] [switch]$GenerateExcel ) # Get module root and configuration paths $ModuleRoot = $PSScriptRoot | Split-Path -Parent $ConfigPath = Join-Path $ModuleRoot "config" # Configuration file paths $ControlConfigPath = Join-Path $ConfigPath "ControlBook_${Configuration}_Config.csv" $PropertyConfigPath = Join-Path $ConfigPath "ControlBook_Property_${Configuration}_Config.csv" $ResultsPath = Join-Path $OutputPath "results_${Configuration}.csv" # Validate input files if (-not (Test-Path $OptimizedReportPath)) { throw "OptimizedReport file not found: $OptimizedReportPath" } if (-not (Test-Path $ControlConfigPath)) { throw "Control configuration file not found: $ControlConfigPath" } if (-not (Test-Path $PropertyConfigPath)) { throw "Property configuration file not found: $PropertyConfigPath" } Write-Host "Running compliance assessment..." -ForegroundColor Yellow Write-Host " Configuration: $Configuration" -ForegroundColor Gray Write-Host " Control Book: $ControlConfigPath" -ForegroundColor Gray Write-Host " Property Book: $PropertyConfigPath" -ForegroundColor Gray Write-Host " Data Source: $OptimizedReportPath" -ForegroundColor Gray try { # Run the control book assessment $Results = Test-ControlBook -ControlConfigPath $ControlConfigPath -PropertyConfigPath $PropertyConfigPath -OptimizedReportPath $OptimizedReportPath -OutputPath $ResultsPath -ConfigurationName $Configuration # Calculate compliance metrics $TotalControls = $Results.Count $PassingControls = ($Results | Where-Object { $_.Pass -eq $true }).Count $FailingControls = $TotalControls - $PassingControls $ComplianceRate = if ($TotalControls -gt 0) { [math]::Round(($PassingControls / $TotalControls) * 100, 2) } else { 0 } $AssessmentResults = @{ TotalControls = $TotalControls PassingControls = $PassingControls FailingControls = $FailingControls ComplianceRate = $ComplianceRate Results = $Results Configuration = $Configuration AssessmentDate = Get-Date } Write-Host "[SUCCESS] Assessment completed successfully" -ForegroundColor Green Write-Host " Total Controls: $TotalControls" -ForegroundColor Gray Write-Host " Passing: $PassingControls" -ForegroundColor Green Write-Host " Failing: $FailingControls" -ForegroundColor Red Write-Host " Compliance Rate: $ComplianceRate%" -ForegroundColor $( if ($ComplianceRate -ge 80) { "Green" } elseif ($ComplianceRate -ge 60) { "Yellow" } else { "Red" } ) # Generate Excel report if requested if ($GenerateExcel) { Write-Host "Generating Excel report..." -ForegroundColor Yellow $ExcelReportPath = Join-Path $OutputPath "MaturityAssessment_${Configuration}_$(Get-Date -Format 'yyyyMMdd_HHmmss').xlsx" try { # Ensure ImportExcel is available if (-not (Get-Module -ListAvailable -Name ImportExcel)) { Write-Host "Installing ImportExcel module..." -ForegroundColor Yellow Install-Module -Name ImportExcel -Force -Scope CurrentUser } Import-Module ImportExcel -Force # Create Excel workbook with multiple sheets $ExcelParams = @{ Path = $ExcelReportPath AutoSize = $true AutoFilter = $true BoldTopRow = $true FreezeTopRow = $true } # Summary sheet $Summary = [PSCustomObject]@{ "Assessment Date" = Get-Date -Format "yyyy-MM-dd HH:mm:ss" "Configuration" = $Configuration "Total Controls" = $TotalControls "Passing Controls" = $PassingControls "Failing Controls" = $FailingControls "Compliance Rate %" = $ComplianceRate "Data Source" = $OptimizedReportPath } $Summary | Export-Excel @ExcelParams -WorksheetName "Summary" # Maturity Level Summary sheet - enriched with descriptions $MaturityLevelSummary = @() $maturityGroups = $Results | Group-Object MaturityLevel foreach ($group in $maturityGroups) { $level = if ($group.Name -eq '' -or $null -eq $group.Name) { '(none)' } else { $group.Name } $total = $group.Group.Count $passing = ($group.Group | Where-Object { $_.Pass -eq $true }).Count $failing = $total - $passing $rate = if ($total -gt 0) { [math]::Round(($passing / $total) * 100, 1) } else { 0 } # Enhanced maturity level descriptions $description = switch ($level.ToLower()) { "1" { "Initial Stage - Basic security controls and foundational data protection measures" } "2" { "Intermediate Stage - Enhanced security policies with automated enforcement and monitoring" } "3" { "Advanced Stage - Comprehensive data security with AI-driven protection and full compliance" } "basic" { "Basic Level - Fundamental security controls implementation" } "intermediate" { "Intermediate Level - Enhanced security with policy automation" } "advanced" { "Advanced Level - Sophisticated security with intelligent protection" } "(none)" { "Unclassified - Controls without assigned maturity levels" } default { "Custom Level - Organization-specific maturity classification: $level" } } $status = if ($rate -ge 90) { "Excellent" } elseif ($rate -ge 80) { "Good" } elseif ($rate -ge 70) { "Acceptable" } elseif ($rate -ge 60) { "Needs Improvement" } else { "Critical" } $MaturityLevelSummary += [PSCustomObject]@{ 'Maturity Level' = $level 'Description' = $description 'Total Controls' = $total 'Passing Controls' = $passing 'Failing Controls' = $failing 'Compliance Rate %' = $rate 'Status' = $status 'Priority' = if ($level -match "^[123]$") { switch ($level) { "1" { "High - Foundation" }; "2" { "Medium - Enhancement" }; "3" { "Low - Optimization" } } } else { "Medium" } } } $MaturityLevelSummary | Export-Excel @ExcelParams -WorksheetName "Maturity Level Summary" # Control Summary sheet - aggregated by Control ID $ControlSummary = $Results | Group-Object -Property ControlID | ForEach-Object { $controlGroup = $_.Group $controlPassed = $controlGroup | Where-Object { $_.Pass -eq $true } $controlFailed = $controlGroup | Where-Object { $_.Pass -eq $false } # A control is considered failed if ANY of its properties fail $overallResult = if ($controlFailed.Count -gt 0) { "Fail" } else { "Pass" } # Concatenate all comments from properties for this control $allComments = @() foreach ($property in $controlGroup) { if ($property.Comments -and $property.Comments.Trim() -ne "") { $propertyComment = "$($property.Properties): $($property.Comments)" $allComments += $propertyComment } } $combinedComments = if ($allComments.Count -gt 0) { $allComments -join " | " } else { "" } [PSCustomObject]@{ "Capability" = $controlGroup[0].Capability "Control ID" = $controlGroup[0].ControlID "Control" = $controlGroup[0].Control "Maturity Level" = $controlGroup[0].MaturityLevel "Total Properties" = $controlGroup.Count "Properties Passed" = $controlPassed.Count "Properties Failed" = $controlFailed.Count "Result" = $overallResult "Comments" = $combinedComments "Configuration" = $controlGroup[0].ConfigurationName } } $ControlSummary | Export-Excel @ExcelParams -WorksheetName "Control Summary" # Detailed results sheet with improved formatting $DetailedResults = $Results | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Name "Result" -Value $(if ($_.Pass -eq $true) { "Pass" } else { "Fail" }) -Force $_ | Select-Object -Property * -ExcludeProperty Pass } $DetailedResults | Export-Excel @ExcelParams -WorksheetName "Detailed Results" Write-Host "[SUCCESS] Excel report generated: $ExcelReportPath" -ForegroundColor Green $AssessmentResults.ExcelReportPath = $ExcelReportPath } catch { Write-Host "[WARNING] Excel generation failed: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host " CSV results are available at: $ResultsPath" -ForegroundColor Gray } } return $AssessmentResults } catch { Write-Host "[ERROR] Assessment failed: $($_.Exception.Message)" -ForegroundColor Red throw } } |