Src/Private/Get-AbrPurviewDSPM.ps1

function Get-AbrPurviewDSPM {
    <#
    .SYNOPSIS
        Used by As Built Report to retrieve Microsoft Purview Data Security Posture Management (DSPM) information.
    .DESCRIPTION
        Collects and reports on Data Security Posture Management configuration in Microsoft Purview,
        including data discovery, sensitive data exposure risks, oversharing insights,
        and DSPM for AI (formerly Microsoft 365 Copilot data security controls).
    .NOTES
        Version: 0.1.0
        Author: Pai Wei Sing
    .EXAMPLE
        Get-AbrPurviewDSPM -TenantId 'contoso.onmicrosoft.com'
    #>

    [CmdletBinding()]
    param (
        [Parameter(Position = 0, Mandatory)]
        [string]$TenantId
    )

    begin {
        Write-PScriboMessage -Message "Collecting Microsoft Purview DSPM information for tenant $TenantId." | Out-Null
        Show-AbrDebugExecutionTime -Start -TitleMessage 'Data Security Posture Management'
    }

    process {

        #region DSPM Overview
        Section -Style Heading2 'Data Security Posture Management (DSPM)' {
            Paragraph "Data Security Posture Management (DSPM) provides visibility into sensitive data risks across Microsoft 365 services. It surfaces oversharing risks, data exposure insights, and AI-related data security controls for tenant $TenantId."
            BlankLine

            #region DSPM for AI / Copilot Data Security
            try {
                $DSPMAIEnabled = $false
                $DSPMAIStatus  = 'Not Configured'

                # Check for any Purview DSPM for AI / Microsoft 365 Copilot data security policies
                # These surface as MIP Auto-labeling or DLP policies scoped to Copilot workloads
                $CopilotDLPPolicies = try {
                    Get-DlpCompliancePolicy -ErrorAction Stop |
                        Where-Object { $_.Workload -match 'Teams|Copilot|AiModel' -or $_.Comment -match 'DSPM|Copilot|AI' }
                } catch { @() }

                $CopilotAutoLabelPolicies = try {
                    Get-AutoSensitivityLabelPolicy -ErrorAction Stop |
                        Where-Object { $_.AppliesTo -match 'All' -or $_.Comment -match 'DSPM|Copilot|AI' }
                } catch { @() }

                $HasCopilotDLP       = ($CopilotDLPPolicies.Count -gt 0)
                $HasAutoLabelCoverage = ($CopilotAutoLabelPolicies.Count -gt 0)

                if ($HasCopilotDLP -or $HasAutoLabelCoverage) {
                    $DSPMAIEnabled = $true
                    $DSPMAIStatus  = 'Configured'
                }

                Section -Style Heading3 'DSPM for AI (Copilot Data Security)' {
                    Paragraph 'DSPM for AI helps discover and protect sensitive data that Microsoft 365 Copilot and other AI tools can access. The controls below reflect policies that govern AI workload data access.'
                    BlankLine

                    $DSPMAISummary = [pscustomobject]@{
                        'DSPM for AI Status'            = $DSPMAIStatus
                        'Copilot-Scoped DLP Policies'   = $CopilotDLPPolicies.Count
                        'Auto-Labeling Policies Active' = $CopilotAutoLabelPolicies.Count
                        'Recommendation'                = if ($DSPMAIEnabled) {
                                                              'Policies detected. Review scope and enforcement mode in Purview portal.'
                                                          } else {
                                                              'No Copilot/AI-scoped policies found. Consider enabling DSPM for AI in the Microsoft Purview portal under Data Security Posture Management.'
                                                          }
                    }

                    $TableParams = @{
                        Name         = 'DSPM for AI Summary'
                        List         = $true
                        ColumnWidths = 40, 60
                    }
                    if ($script:Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" }
                    $DSPMAISummary | Table @TableParams

                    # HealthCheck
                    if ($script:HealthCheck.Purview.DSPM) {
                        if (-not $DSPMAIEnabled) {
                            Paragraph "HEALTH CHECK: DSPM for AI is not configured. Sensitive data accessible to Copilot and AI tools may not be protected. Enable DSPM for AI in the Microsoft Purview portal." -Style Warning
                        }
                    }
                }
            } catch {
                Write-PScriboMessage -IsWarning "DSPM for AI: Unable to retrieve data. Error: $($_.Exception.Message)"
            }
            #endregion

            #region Oversharing Insights
            try {
                Section -Style Heading3 'Oversharing Insights' {
                    Paragraph 'Oversharing insights identify sensitive content shared broadly (e.g., "Everyone" or external recipients). The following DLP policies are configured to detect and reduce oversharing risks.'
                    BlankLine

                    # Surface DLP policies that target SharePoint/OneDrive sharing scenarios
                    $OversharingPolicies = try {
                        Get-DlpCompliancePolicy -ErrorAction Stop |
                            Where-Object {
                                $_.Workload -match 'SharePoint|OneDrive' -and $_.Enabled -eq $true
                            }
                    } catch { @() }

                    if ($OversharingPolicies) {
                        $OutObj = [System.Collections.ArrayList]::new()
                        foreach ($Policy in $OversharingPolicies) {
                            try {
                                $null = $OutObj.Add([pscustomobject]@{
                                    'Policy Name' = $Policy.Name
                                    'Workload'    = ($Policy.Workload -join ', ')
                                    'Mode'        = $Policy.Mode
                                    'Enabled'     = if ($Policy.Enabled) { 'Yes' } else { 'No' }
                                    'Priority'    = $Policy.Priority
                                })
                            } catch { }
                        }

                        if ($OutObj.Count -gt 0) {
                            $TableParams = @{
                                Name         = "Oversharing DLP Policies - $TenantId"
                                List         = $false
                                ColumnWidths = 35, 20, 15, 10, 20
                            }
                            if ($script:Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" }
                            $OutObj | Table @TableParams
                        }
                    } else {
                        Paragraph 'No SharePoint/OneDrive DLP policies found. Consider creating oversharing policies to prevent sensitive data from being shared broadly.'
                        if ($script:HealthCheck.Purview.DSPM) {
                            Paragraph 'HEALTH CHECK: No oversharing DLP policies detected for SharePoint or OneDrive. Sensitive files may be shared without controls.' -Style Warning
                        }
                    }
                }
            } catch {
                Write-PScriboMessage -IsWarning "DSPM Oversharing: Unable to retrieve data. Error: $($_.Exception.Message)"
            }
            #endregion

            #region Sensitive Data Exposure Summary
            try {
                Section -Style Heading3 'Sensitive Data Exposure Risk Summary' {
                    Paragraph 'The following summarises DLP and auto-labeling policy coverage across key workloads as an indicator of sensitive data exposure risk posture.'
                    BlankLine

                    # Count enabled DLP policies per workload
                    $AllDLPPolicies = try { Get-DlpCompliancePolicy -ErrorAction Stop | Where-Object { $_.Enabled -eq $true } } catch { @() }

                    $WorkloadMap = [ordered]@{
                        'Exchange (Email)'        = 'Exchange'
                        'SharePoint'              = 'SharePoint'
                        'OneDrive'                = 'OneDrive'
                        'Teams'                   = 'Teams'
                        'Endpoint (Devices)'      = 'Devices'
                    }

                    $ExposureObj = [System.Collections.ArrayList]::new()
                    foreach ($Label in $WorkloadMap.Keys) {
                        $Workload    = $WorkloadMap[$Label]
                        $PolicyCount = ($AllDLPPolicies | Where-Object { $_.Workload -match $Workload }).Count
                        $RiskLevel   = if ($PolicyCount -eq 0) { 'High — No DLP Coverage' }
                                       elseif ($PolicyCount -lt 2) { 'Medium — Limited Coverage' }
                                       else { 'Low — Policies Present' }

                        $null = $ExposureObj.Add([pscustomobject]@{
                            'Workload'        = $Label
                            'DLP Policy Count' = $PolicyCount
                            'Risk Indicator'  = $RiskLevel
                        })
                    }

                    $TableParams = @{
                        Name         = "Sensitive Data Exposure Risk - $TenantId"
                        List         = $false
                        ColumnWidths = 35, 20, 45
                    }
                    if ($script:Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" }
                    $ExposureObj | Table @TableParams
                }
            } catch {
                Write-PScriboMessage -IsWarning "DSPM Exposure Summary: Unable to retrieve data. Error: $($_.Exception.Message)"
            }
            #endregion

        } # end Section DSPM
        #endregion

    } # end process

    end {
        Show-AbrDebugExecutionTime -End -TitleMessage 'Data Security Posture Management'
    }
}