CloudSecurity/Get-CloudComplianceStatus.ps1

function Get-CloudComplianceStatus {
    <#
    .SYNOPSIS
        Retrieves cloud compliance status against regulatory frameworks
 
    .DESCRIPTION
        Reports cloud environment compliance against various frameworks:
        CIS, ISO27001, NIST, GDPR, HIPAA, SOC2, AzureSecurityBenchmark.
 
        Automated evaluation of these controls requires framework-specific
        Microsoft Graph/API queries that are not yet implemented. Controls in
        the built-in catalog are therefore returned with Status 'NotEvaluated'
        and the ComplianceScore is $null when no control was actually evaluated.
 
    .PARAMETER Framework
        Compliance framework (Default: CIS)
 
    .PARAMETER IncludeRemediation
        Include remediation steps
 
    .PARAMETER ExportPath
        Path to save compliance report
 
    .PARAMETER Format
        Report format: HTML, JSON, CSV, or All (Default: HTML)
 
    .EXAMPLE
        Get-CloudComplianceStatus -Framework CIS
 
    .OUTPUTS
        PSCustomObject with Framework, Controls, Summary, and ComplianceScore
        ($null when no controls were evaluated).
    #>


    [CmdletBinding()]
    param(
        [ValidateSet('CIS', 'ISO27001', 'NIST', 'GDPR', 'HIPAA', 'SOC2', 'AzureSecurityBenchmark')]
        [string]$Framework = 'CIS',
        [switch]$IncludeRemediation,
        [string]$ExportPath,
        [ValidateSet('HTML', 'JSON', 'CSV', 'All')]
        [string]$Format = 'HTML'
    )

    begin {
        Write-Host "========================================" -ForegroundColor Cyan
        Write-Host " CLOUD COMPLIANCE ASSESSMENT" -ForegroundColor Cyan
        Write-Host "========================================" -ForegroundColor Cyan
        Write-Host "Framework: $Framework" -ForegroundColor Yellow

        # Initialize results
        $results = [PSCustomObject]@{
            AssessmentDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            Framework = $Framework
            FrameworkVersion = "Latest"
            Controls = @()
            ComplianceScore = $null
            Summary = @{
                TotalControls = 0
                Evaluated = 0
                NotEvaluated = 0
                Compliant = 0
                NonCompliant = 0
                PartiallyCompliant = 0
            }
        }
    }

    process {
        try {
            Write-Host "`nLoading $Framework control catalog..." -ForegroundColor Cyan

            $catalog = @()

            # Catalog of framework control references. These entries identify the
            # controls only; their compliance status is NOT evaluated (see below).
            switch ($Framework) {
                'CIS' {
                    $catalog = @(
                        @{
                            ControlId = "1.1.1"
                            Title = "Ensure multifactor authentication is enabled"
                            Category = "Identity"
                            Severity = "Critical"
                            Remediation = "Enable MFA via Conditional Access"
                        },
                        @{
                            ControlId = "1.1.2"
                            Title = "Ensure global admins are limited"
                            Category = "Identity"
                            Severity = "High"
                            Remediation = "N/A"
                        }
                    )
                }

                'GDPR' {
                    $catalog = @(
                        @{
                            ControlId = "Art. 32"
                            Title = "Security of processing"
                            Category = "Technical Measures"
                            Severity = "Critical"
                            Remediation = "N/A"
                        }
                    )
                }

                'NIST' {
                    $catalog = @(
                        @{
                            ControlId = "ID.AM-1"
                            Title = "Physical devices inventoried"
                            Category = "Identify"
                            Severity = "Medium"
                            Remediation = "N/A"
                        }
                    )
                }

                default {
                    $catalog = @()
                }
            }

            if (@($catalog).Count -eq 0) {
                Write-Warning "No control catalog is defined for framework '$Framework'."
            }

            Write-Warning "Automated evaluation of $Framework controls is not implemented: it requires framework-specific Microsoft Graph/API queries. All listed controls are returned with Status 'NotEvaluated' and are excluded from the compliance score."

            # Process controls
            $notEvaluatedNote = "Not evaluated: automated cloud compliance evaluation of this control requires framework-specific Microsoft Graph/API queries that are not yet implemented."

            foreach ($control in $catalog) {
                $results.Controls += [PSCustomObject]@{
                    ControlId = $control.ControlId
                    Title = $control.Title
                    Category = $control.Category
                    Status = "NotEvaluated"
                    Severity = $control.Severity
                    Note = $notEvaluatedNote
                    Remediation = if ($IncludeRemediation) { $control.Remediation } else { $null }
                }

                $results.Summary.TotalControls++
                $results.Summary.NotEvaluated++
            }

            # Calculate score from evaluated controls only; with none evaluated the
            # score stays $null instead of implying a pass rate that was never measured.
            $evaluatedCount = $results.Summary.Compliant + $results.Summary.NonCompliant + $results.Summary.PartiallyCompliant
            $results.Summary.Evaluated = $evaluatedCount

            if ($evaluatedCount -gt 0) {
                $compliantCount = $results.Summary.Compliant + ($results.Summary.PartiallyCompliant * 0.5)
                $results.ComplianceScore = [Math]::Round(($compliantCount / $evaluatedCount) * 100, 1)
            }

            # Export if requested
            if ($ExportPath) {
                Write-Host "`nExporting reports..." -ForegroundColor Cyan

                if (-not (Test-Path $ExportPath)) {
                    New-Item -Path $ExportPath -ItemType Directory -Force | Out-Null
                }

                $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"

                if ($Format -in @('JSON', 'All')) {
                    $jsonPath = Join-Path $ExportPath "Compliance_${Framework}_$timestamp.json"
                    $results | ConvertTo-Json -Depth 10 | Out-File $jsonPath -Encoding UTF8
                    Write-Host "Exported JSON: $jsonPath" -ForegroundColor Green
                }

                if ($Format -in @('CSV', 'All')) {
                    $csvPath = Join-Path $ExportPath "Compliance_${Framework}_$timestamp.csv"
                    $results.Controls | Export-Csv $csvPath -NoTypeInformation
                    Write-Host "Exported CSV: $csvPath" -ForegroundColor Green
                }

                if ($Format -in @('HTML', 'All')) {
                    $htmlPath = Join-Path $ExportPath "Compliance_${Framework}_$timestamp.html"
                    $htmlContent = Generate-CloudComplianceHTML -Results $results
                    $htmlContent | Out-File $htmlPath -Encoding UTF8
                    Write-Host "Exported HTML: $htmlPath" -ForegroundColor Green
                }
            }
        }
        catch {
            Write-Error "Error during assessment: $_"
            throw
        }
    }

    end {
        Write-Host "`n========================================" -ForegroundColor Green
        Write-Host " COMPLIANCE ASSESSMENT COMPLETE" -ForegroundColor Green
        Write-Host "========================================" -ForegroundColor Green

        if ($null -ne $results.ComplianceScore) {
            $scoreColor = if ($results.ComplianceScore -ge 80) { 'Green' }
                          elseif ($results.ComplianceScore -ge 60) { 'Yellow' }
                          else { 'Red' }
            Write-Host "`nCompliance Score: $($results.ComplianceScore)%" -ForegroundColor $scoreColor
        }
        else {
            Write-Host "`nCompliance Score: N/A (no controls were evaluated)" -ForegroundColor Yellow
        }

        Write-Host "Framework: $($results.Framework)" -ForegroundColor Cyan
        Write-Host "Total Controls: $($results.Summary.TotalControls)" -ForegroundColor White
        Write-Host "Evaluated: $($results.Summary.Evaluated)" -ForegroundColor White
        Write-Host "Not Evaluated: $($results.Summary.NotEvaluated)" -ForegroundColor Yellow
        Write-Host "Compliant: $($results.Summary.Compliant)" -ForegroundColor Green
        Write-Host "Non-Compliant: $($results.Summary.NonCompliant)" -ForegroundColor Red

        return $results
    }
}

function Generate-CloudComplianceHTML {
    param($Results)

    $hasScore = ($null -ne $Results) -and ($null -ne $Results.ComplianceScore)

    if ($hasScore) {
        $scoreColor = if ($Results.ComplianceScore -ge 80) { '#107c10' }
                      elseif ($Results.ComplianceScore -ge 60) { '#f7630c' }
                      else { '#d13438' }
        $scoreDisplay = "$($Results.ComplianceScore)%"
    }
    else {
        $scoreColor = '#605e5c'
        $scoreDisplay = "N/A"
    }

    $html = @'
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Cloud Compliance Status Report</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
        .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        h1 { color: #0078d4; border-bottom: 3px solid #0078d4; padding-bottom: 10px; }
        h2 { color: #106ebe; margin-top: 30px; }
        table { width: 100%; border-collapse: collapse; margin: 20px 0; }
        th { background: #0078d4; color: white; padding: 12px; text-align: left; }
        td { padding: 10px; border-bottom: 1px solid #ddd; }
        tr:hover { background: #f8f9fa; }
        .compliant { color: #107c10; font-weight: bold; }
        .non-compliant { color: #d13438; font-weight: bold; }
        .partial { color: #f7630c; font-weight: bold; }
        .not-evaluated { color: #605e5c; font-weight: bold; }
        .score-box { text-align: center; padding: 30px; margin: 20px 0; border-radius: 10px; color: white; }
        .score-value { font-size: 48px; font-weight: bold; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Cloud Compliance Status Report</h1>
'@


    $html += @"
        <div class="score-box" style="background: $scoreColor;">
            <div class="score-value">$scoreDisplay</div>
            <div>Compliance Score</div>
        </div>
 
        <h2>Framework Information</h2>
        <p><strong>Framework:</strong> $($Results.Framework)</p>
        <p><strong>Version:</strong> $($Results.FrameworkVersion)</p>
        <p><strong>Assessment Date:</strong> $($Results.AssessmentDate)</p>
 
        <h2>Control Summary</h2>
        <p><strong>Total Controls:</strong> $($Results.Summary.TotalControls)</p>
        <p><strong>Evaluated:</strong> $($Results.Summary.Evaluated)</p>
        <p><strong>Not Evaluated:</strong> $($Results.Summary.NotEvaluated)</p>
        <p><strong>Compliant:</strong> $($Results.Summary.Compliant)</p>
        <p><strong>Non-Compliant:</strong> $($Results.Summary.NonCompliant)</p>
 
        <h2>Compliance Controls</h2>
        <table>
            <thead>
                <tr>
                    <th>Control ID</th>
                    <th>Title</th>
                    <th>Category</th>
                    <th>Severity</th>
                    <th>Status</th>
                </tr>
            </thead>
            <tbody>
"@


    foreach ($control in $Results.Controls) {
        $statusClass = switch ($control.Status) {
            'Compliant' { 'compliant' }
            'Non-Compliant' { 'non-compliant' }
            'Partially Compliant' { 'partial' }
            default { 'not-evaluated' }
        }

        $html += @"
                <tr>
                    <td>$($control.ControlId)</td>
                    <td>$($control.Title)</td>
                    <td>$($control.Category)</td>
                    <td>$($control.Severity)</td>
                    <td class="$statusClass">$($control.Status)</td>
                </tr>
"@

    }

    $html += @'
            </tbody>
        </table>
 
        <div style="margin-top: 40px; padding-top: 20px; border-top: 2px solid #ddd; text-align: center; color: #605e5c; font-size: 12px;">
            <p>Generated by WindowsSecurityAudit Module</p>
        </div>
    </div>
</body>
</html>
'@


    return $html
}