Public/Get-CustomSecurityAttributesReport.ps1

<#
.SYNOPSIS
    Generates an interactive HTML report of custom security attributes across users, devices, and enterprise apps.
    Connect first with Connect-RKGraph; this cmdlet uses the existing connection.
.DESCRIPTION
    Queries Microsoft Graph for custom security attributes assigned to users, devices, and service principals.
    Auto-discovers attribute sets or accepts a specific set. Generates an interactive report with:
    - Overview tab with coverage matrix (which entities have which attribute sets)
    - Dynamic tabs per attribute set with sub-sections for users, devices, and enterprise apps
    - DataTables with search, export (Excel/CSV/PDF), column visibility, and dark/light theme toggle
.PARAMETER AttributeSet
    Specific attribute set to report on. If not specified, auto-discovers and reports on all attribute sets.
.PARAMETER SendEmail
    Send the report as an email attachment via Microsoft Graph Mail.Send.
.PARAMETER Recipient
    Email addresses to send the report to. Required when -SendEmail is used.
.PARAMETER From
    Sender email address. If omitted, sends as the currently authenticated user.
.PARAMETER ExportPath
    Full path for the HTML report file. Defaults to current directory.
.PARAMETER DebugMode
    Enable verbose debug output.
.EXAMPLE
    Get-CustomSecurityAttributesReport
    Auto-discovers all attribute sets and generates a full report.
.EXAMPLE
    Get-CustomSecurityAttributesReport -AttributeSet "ComplianceData"
    Report on a specific attribute set only.
.EXAMPLE
    Get-CustomSecurityAttributesReport -SendEmail -Recipient "admin@contoso.com"
    Generate report and email it.
#>

function Get-CustomSecurityAttributesReport {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$AttributeSet,

        [Parameter(Mandatory = $false)]
        [switch]$SendEmail,

        [Parameter(Mandatory = $false)]
        [string[]]$Recipient,

        [Parameter(Mandatory = $false)]
        [string]$From,

        [Parameter(Mandatory = $false)]
        [string]$ExportPath,

        [Parameter(Mandatory = $false)]
        [switch]$DebugMode
    )

    $ErrorActionPreference = 'Stop'
    try {
        $ctx = Get-MgContext -ErrorAction SilentlyContinue
        if (-not $ctx) { throw 'Not connected to Microsoft Graph. Run Connect-RKGraph first.' }

        # Get tenant information
        $tenantInfo = Invoke-MgGraphRequest -Uri 'v1.0/organization' -Method Get -OutputType PSObject
        $tenantName = $tenantInfo.value[0].displayName

        # Fetch attribute data across all entity types
        $dataParams = @{ DebugMode = $DebugMode }
        if ($AttributeSet) { $dataParams['AttributeSet'] = $AttributeSet }
        $reportData = Get-CustomSecurityAttributeData @dataParams

        $totalEntities = $reportData.Counts.Users + $reportData.Counts.Devices + $reportData.Counts.Apps
        if ($totalEntities -eq 0) {
            Write-Host 'No entities found with custom security attributes.' -ForegroundColor Yellow
            return
        }

        Write-Host "Found $($reportData.Counts.Users) user(s), $($reportData.Counts.Devices) device(s), $($reportData.Counts.Apps) app(s) with attributes." -ForegroundColor Green

        # Generate HTML report
        $htmlPath = New-CustomSecurityAttributesHTMLReport -TenantName $tenantName -ReportData $reportData -ExportPath $ExportPath

        # Send email if requested
        if ($SendEmail -and $Recipient) {
            $subject = "$tenantName - Custom Security Attributes Report"
            $bodyHtml = @"
<html><body style="font-family: 'Source Serif 4', Georgia, serif;">
<h2>Custom Security Attributes Report</h2>
<p>Attached is the latest Custom Security Attributes report for <strong>$tenantName</strong>.</p>
<p>Open the attached HTML in a browser for the interactive dashboard.</p>
<p style='color:#787468;'>Generated by RKSolutions - please do not reply.</p>
</body></html>
"@

            $emailSent = Send-EmailWithAttachment -Recipient $Recipient -AttachmentPath $htmlPath -From $From -Subject $subject -BodyHtml $bodyHtml
            if ($emailSent) { Write-Host 'INFO: Email sent successfully.' -ForegroundColor Green } else { Write-Host 'ERROR: Failed to send email.' -ForegroundColor Red }
        }

        if ($SendEmail -and (Test-Path -Path $htmlPath)) {
            Remove-Item -Path $htmlPath -Force
            Write-Host 'INFO: Temporary report file deleted.' -ForegroundColor Green
        }
    }
    catch { Write-Error "Error: $_"; throw $_ }
}