Security/Get-ComplianceSecurityConfig.ps1
|
<# .SYNOPSIS Collects Microsoft Purview/Compliance security configuration settings for M365 assessment. .DESCRIPTION Queries Security & Compliance PowerShell for compliance-related security settings including unified audit log, DLP policies, sensitivity labels, alert policies, auto-labeling, and communication compliance. Returns a structured inventory of settings with current values and CIS benchmark recommendations. Requires an active Security & Compliance (Purview) connection. .PARAMETER OutputPath Optional path to export results as CSV. If not specified, results are returned to the pipeline. .EXAMPLE PS> . .\Common\Connect-Service.ps1 PS> Connect-Service -Service Purview PS> .\Security\Get-ComplianceSecurityConfig.ps1 Displays Purview/Compliance security configuration settings. .EXAMPLE PS> .\Security\Get-ComplianceSecurityConfig.ps1 -OutputPath '.\compliance-security-config.csv' Exports the security configuration to CSV. .NOTES Author: Daren9m Settings checked are aligned with CIS Microsoft 365 Foundations Benchmark v6.0.1 recommendations. #> [CmdletBinding()] param( [Parameter()] [ValidateNotNullOrEmpty()] [string]$OutputPath ) # Stop on errors: API failures should halt this collector rather than produce partial results. $ErrorActionPreference = 'Stop' # Load shared security-config helpers $_scriptDir = if ($MyInvocation.MyCommand.Path) { Split-Path -Parent $MyInvocation.MyCommand.Path } else { $PSScriptRoot } . (Join-Path -Path $_scriptDir -ChildPath '..\Common\SecurityConfigHelper.ps1') $ctx = Initialize-SecurityConfig $settings = $ctx.Settings $checkIdCounter = $ctx.CheckIdCounter function Add-Setting { param( [string]$Category, [string]$Setting, [string]$CurrentValue, [string]$RecommendedValue, [string]$Status, [string]$CheckId = '', [string]$Remediation = '' ) $p = @{ Settings = $settings CheckIdCounter = $checkIdCounter Category = $Category Setting = $Setting CurrentValue = $CurrentValue RecommendedValue = $RecommendedValue Status = $Status CheckId = $CheckId Remediation = $Remediation } Add-SecuritySetting @p } # ------------------------------------------------------------------ # 1. Unified Audit Log (CIS 3.1.1) # ------------------------------------------------------------------ try { Write-Verbose "Checking unified audit log configuration..." $auditLogAvailable = Get-Command -Name Get-AdminAuditLogConfig -ErrorAction SilentlyContinue if ($auditLogAvailable) { $auditConfig = Get-AdminAuditLogConfig -ErrorAction Stop $auditEnabled = $auditConfig.UnifiedAuditLogIngestionEnabled $settingParams = @{ Category = 'Audit' Setting = 'Unified Audit Log (UAL) Ingestion' CurrentValue = "$auditEnabled" RecommendedValue = 'True' Status = if ($auditEnabled) { 'Pass' } else { 'Fail' } CheckId = 'COMPLIANCE-AUDIT-001' Remediation = 'Run: Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true. Microsoft Purview > Audit > Start recording user and admin activity.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Audit' Setting = 'Unified Audit Log (UAL) Ingestion' CurrentValue = 'Cmdlet not available' RecommendedValue = 'True' Status = 'Review' CheckId = 'COMPLIANCE-AUDIT-001' Remediation = 'Connect to Security & Compliance PowerShell to check audit log configuration.' } Add-Setting @settingParams } } catch { Write-Warning "Could not check unified audit log: $_" } # ------------------------------------------------------------------ # 2. DLP Policies Exist (CIS 3.2.1) # ------------------------------------------------------------------ try { Write-Verbose "Checking DLP policies..." $dlpAvailable = Get-Command -Name Get-DlpCompliancePolicy -ErrorAction SilentlyContinue if ($dlpAvailable) { $dlpPolicies = Get-DlpCompliancePolicy -ErrorAction Stop $enabledPolicies = @($dlpPolicies | Where-Object { $_.Enabled -eq $true }) if ($enabledPolicies.Count -gt 0) { $settingParams = @{ Category = 'Data Loss Prevention' Setting = 'DLP Policies' CurrentValue = "$($enabledPolicies.Count) enabled (of $(@($dlpPolicies).Count) total)" RecommendedValue = 'At least 1 enabled' Status = 'Pass' CheckId = 'COMPLIANCE-DLP-001' Remediation = 'No action needed.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Data Loss Prevention' Setting = 'DLP Policies' CurrentValue = $(if (@($dlpPolicies).Count -eq 0) { 'None configured' } else { "$(@($dlpPolicies).Count) policies (none enabled)" }) RecommendedValue = 'At least 1 enabled' Status = 'Fail' CheckId = 'COMPLIANCE-DLP-001' Remediation = 'Microsoft Purview > Data loss prevention > Policies > Create a DLP policy covering sensitive information types relevant to your organization.' } Add-Setting @settingParams } # CIS 3.2.2 -- DLP covers Teams $teamsPolicies = @($enabledPolicies | Where-Object { $_.TeamsLocation -or ($_.Workload -and $_.Workload -match 'Teams') }) if ($teamsPolicies.Count -gt 0) { $settingParams = @{ Category = 'Data Loss Prevention' Setting = 'DLP Covers Teams' CurrentValue = "$($teamsPolicies.Count) policies include Teams" RecommendedValue = 'At least 1 policy covers Teams' Status = 'Pass' CheckId = 'COMPLIANCE-DLP-002' Remediation = 'No action needed.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Data Loss Prevention' Setting = 'DLP Covers Teams' CurrentValue = 'No DLP policies cover Teams' RecommendedValue = 'At least 1 policy covers Teams' Status = 'Fail' CheckId = 'COMPLIANCE-DLP-002' Remediation = 'Microsoft Purview > Data loss prevention > Policies > Edit an existing policy or create new > Include Teams chat and channel messages location.' } Add-Setting @settingParams } # DLP workload coverage -- Exchange and SharePoint/OneDrive $exoPolicies = @($enabledPolicies | Where-Object { $_.ExchangeLocation -or ($_.Workload -and $_.Workload -match 'Exchange') }) $spodPolicies = @($enabledPolicies | Where-Object { $_.SharePointLocation -or $_.OneDriveLocation -or ($_.Workload -and $_.Workload -match 'SharePoint') }) $coverageStatus = if ($exoPolicies.Count -gt 0 -and $spodPolicies.Count -gt 0) { 'Pass' } elseif ($exoPolicies.Count -gt 0 -or $spodPolicies.Count -gt 0) { 'Warning' } else { 'Fail' } $settingParams = @{ Category = 'Data Loss Prevention' Setting = 'DLP Workload Coverage' CurrentValue = "Exchange: $($exoPolicies.Count -gt 0), SharePoint/OneDrive: $($spodPolicies.Count -gt 0)" RecommendedValue = 'Policies cover Exchange and SharePoint/OneDrive' Status = $coverageStatus CheckId = 'COMPLIANCE-DLP-003' Remediation = 'Microsoft Purview > Data loss prevention > Policies > Edit existing policies to include Exchange email and SharePoint/OneDrive locations for comprehensive data protection.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Data Loss Prevention' Setting = 'DLP Policies' CurrentValue = 'Cmdlet not available' RecommendedValue = 'At least 1 enabled' Status = 'Review' CheckId = 'COMPLIANCE-DLP-001' Remediation = 'Connect to Security & Compliance PowerShell to check DLP policies.' } Add-Setting @settingParams } } catch { Write-Warning "Could not check DLP policies: $_" } # ------------------------------------------------------------------ # 3. Sensitivity Labels Published (CIS 3.3.1) # ------------------------------------------------------------------ try { Write-Verbose "Checking sensitivity label policies..." $labelAvailable = Get-Command -Name Get-LabelPolicy -ErrorAction SilentlyContinue if ($labelAvailable) { $labelPolicies = Get-LabelPolicy -ErrorAction Stop if (@($labelPolicies).Count -gt 0) { $settingParams = @{ Category = 'Information Protection' Setting = 'Sensitivity Label Policies' CurrentValue = "$(@($labelPolicies).Count) policies published" RecommendedValue = 'At least 1 published' Status = 'Pass' CheckId = 'COMPLIANCE-LABELS-001' Remediation = 'No action needed.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Information Protection' Setting = 'Sensitivity Label Policies' CurrentValue = 'None published' RecommendedValue = 'At least 1 published' Status = 'Fail' CheckId = 'COMPLIANCE-LABELS-001' Remediation = 'Microsoft Purview > Information protection > Labels > Create and publish sensitivity labels. Then create a label policy to deploy them to users.' } Add-Setting @settingParams } } else { $settingParams = @{ Category = 'Information Protection' Setting = 'Sensitivity Label Policies' CurrentValue = 'Cmdlet not available' RecommendedValue = 'At least 1 published' Status = 'Review' CheckId = 'COMPLIANCE-LABELS-001' Remediation = 'Connect to Security & Compliance PowerShell to check sensitivity labels.' } Add-Setting @settingParams } } catch { Write-Warning "Could not check sensitivity labels: $_" } # ------------------------------------------------------------------ # 4. Security Alert Policies # ------------------------------------------------------------------ try { Write-Verbose "Checking security alert policies..." $alertAvailable = Get-Command -Name Get-ProtectionAlert -ErrorAction SilentlyContinue if ($alertAvailable) { $alerts = @(Get-ProtectionAlert -ErrorAction Stop) $enabledAlerts = @($alerts | Where-Object { -not $_.Disabled }) $alertStatus = if ($enabledAlerts.Count -gt 0) { 'Pass' } else { 'Fail' } $settingParams = @{ Category = 'Alert Policies' Setting = 'Security Alert Policies Enabled' CurrentValue = "$($enabledAlerts.Count) enabled (of $($alerts.Count) total)" RecommendedValue = 'At least 1 enabled' Status = $alertStatus CheckId = 'COMPLIANCE-ALERTPOLICY-001' Remediation = 'Microsoft Purview > Alert policies > Review and enable default alert policies. Ensure high-severity policies for suspicious activity, malware, and privilege escalation are active.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Alert Policies' Setting = 'Security Alert Policies Enabled' CurrentValue = 'Cmdlet not available' RecommendedValue = 'At least 1 enabled' Status = 'Review' CheckId = 'COMPLIANCE-ALERTPOLICY-001' Remediation = 'Connect to Security & Compliance PowerShell to check alert policies.' } Add-Setting @settingParams } } catch { Write-Warning "Could not check alert policies: $_" } # ------------------------------------------------------------------ # 5. Auto-Sensitivity Labeling Policies (requires AIP P2 / E5) # ------------------------------------------------------------------ try { Write-Verbose "Checking auto-labeling policies..." $autoLabelAvailable = Get-Command -Name Get-AutoSensitivityLabelPolicy -ErrorAction SilentlyContinue if ($autoLabelAvailable) { $autoLabelPolicies = @(Get-AutoSensitivityLabelPolicy -ErrorAction Stop) $enabledAutoLabel = @($autoLabelPolicies | Where-Object { $_.Enabled -eq $true }) if ($enabledAutoLabel.Count -gt 0) { $autoLabelCount = $enabledAutoLabel.Count $settingParams = @{ Category = 'Information Protection' Setting = 'Auto-Sensitivity Labeling Policies' CurrentValue = "$autoLabelCount enabled auto-labeling $(if ($autoLabelCount -eq 1) { 'policy' } else { 'policies' })" RecommendedValue = 'At least 1 enabled' Status = 'Pass' CheckId = 'COMPLIANCE-LABELS-002' Remediation = 'No action needed.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Information Protection' Setting = 'Auto-Sensitivity Labeling Policies' CurrentValue = if ($autoLabelPolicies.Count -eq 0) { 'None configured' } else { "$($autoLabelPolicies.Count) policies (none enabled)" } RecommendedValue = 'At least 1 enabled' Status = 'Fail' CheckId = 'COMPLIANCE-LABELS-002' Remediation = 'Microsoft Purview > Information protection > Auto-labeling > Create a policy to automatically classify sensitive content. Requires Azure Information Protection P2 (E5 or E5 Compliance).' } Add-Setting @settingParams } } else { $settingParams = @{ Category = 'Information Protection' Setting = 'Auto-Sensitivity Labeling Policies' CurrentValue = 'Cmdlet not available' RecommendedValue = 'At least 1 enabled' Status = 'Review' CheckId = 'COMPLIANCE-LABELS-002' Remediation = 'Auto-labeling requires Azure Information Protection P2 (E5 or E5 Compliance). Connect to Security & Compliance PowerShell to verify.' } Add-Setting @settingParams } } catch { Write-Warning "Could not check auto-labeling policies: $_" } # ------------------------------------------------------------------ # 6. Communication Compliance Policies (requires E5 Compliance) # ------------------------------------------------------------------ try { Write-Verbose "Checking communication compliance policies..." $commAvailable = Get-Command -Name Get-CommunicationCompliancePolicy -ErrorAction SilentlyContinue if ($commAvailable) { $commPolicies = @(Get-CommunicationCompliancePolicy -ErrorAction Stop) $enabledComm = @($commPolicies | Where-Object { $_.Enabled -eq $true }) if ($enabledComm.Count -gt 0) { $enabledCommCount = $enabledComm.Count $settingParams = @{ Category = 'Communication Compliance' Setting = 'Communication Compliance Policies' CurrentValue = "$enabledCommCount enabled $(if ($enabledCommCount -eq 1) { 'policy' } else { 'policies' })" RecommendedValue = 'At least 1 enabled' Status = 'Pass' CheckId = 'COMPLIANCE-COMMS-001' Remediation = 'No action needed.' } Add-Setting @settingParams } else { $settingParams = @{ Category = 'Communication Compliance' Setting = 'Communication Compliance Policies' CurrentValue = if ($commPolicies.Count -eq 0) { 'None configured' } else { "$($commPolicies.Count) policies (none enabled)" } RecommendedValue = 'At least 1 enabled' Status = 'Warning' CheckId = 'COMPLIANCE-COMMS-001' Remediation = 'Microsoft Purview > Communication compliance > Create a policy to monitor communications for policy violations and insider risk. Requires E5 Compliance licensing.' } Add-Setting @settingParams } } else { $settingParams = @{ Category = 'Communication Compliance' Setting = 'Communication Compliance Policies' CurrentValue = 'Cmdlet not available' RecommendedValue = 'At least 1 enabled' Status = 'Review' CheckId = 'COMPLIANCE-COMMS-001' Remediation = 'Communication compliance requires E5 Compliance licensing. Connect to Security & Compliance PowerShell to verify policy status.' } Add-Setting @settingParams } } catch { Write-Warning "Could not check communication compliance policies: $_" } # ------------------------------------------------------------------ # Output # ------------------------------------------------------------------ Export-SecurityConfigReport -Settings $settings -OutputPath $OutputPath -ServiceLabel 'Compliance' |