Private/Reporting.Html.ps1

function Complete-M365SnapshotHtmlReport {
    param(
        [Parameter(Mandatory=$true)]
        [string]$HtmlContent,

        [Parameter(Mandatory=$true)]
        [string]$ReportPath
    )

    $HtmlContent = $HtmlContent -replace '&lt;br&gt;', '<br>'

    $HtmlContent = [regex]::Replace(
        $HtmlContent,
        '__APP_PORTAL_LINK__(?<id>[0-9a-fA-F\-]{36})\|(?<url>https?://[^<\s_]+(?:_[^<\s]+)?)?(?:__END_APP_PORTAL_LINK__)?',
        {
            param($match)

            $appId = $match.Groups['id'].Value
            $url = $match.Groups['url'].Value

            if ([string]::IsNullOrWhiteSpace($url)) {
                $url = "https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/$appId"
            }

            $safeHref = [System.Net.WebUtility]::HtmlEncode($url)
            $safeText = [System.Net.WebUtility]::HtmlEncode($appId)
            return ('<a href="{0}" target="_blank" rel="noopener noreferrer">{1}</a>' -f $safeHref, $safeText)
        },
        [System.Text.RegularExpressions.RegexOptions]::IgnoreCase
    )

    $HtmlContent = [regex]::Replace(
        $HtmlContent,
        '(?<=<td>|<br>)([A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,})(?=</td>|<br>)',
        {
            param($match)

            $email = $match.Groups[1].Value
            $safeEmail = [System.Net.WebUtility]::HtmlEncode($email)
            return ('<a href="mailto:{0}">{1}</a>' -f $safeEmail, $safeEmail)
        },
        [System.Text.RegularExpressions.RegexOptions]::IgnoreCase
    )

    $HtmlContent = [regex]::Replace(
        $HtmlContent,
        '(?<=<td>)([^<]+?)\s*\((https?://[^<]+)\)(?=</td>)',
        {
            param($match)

            $title = $match.Groups[1].Value.Trim()
            $url = $match.Groups[2].Value

            $safeHref = [System.Net.WebUtility]::HtmlEncode($url)
            $safeText = [System.Net.WebUtility]::HtmlEncode($title)
            return ('<a href="{0}" target="_blank" rel="noopener noreferrer">{1}</a>' -f $safeHref, $safeText)
        }
    )

    $HtmlContent = [regex]::Replace(
        $HtmlContent,
        '(?<=<td>)(https?://[^<]+)(?=</td>)',
        {
            param($match)

            $url = $match.Groups[1].Value
            $displayText = $url

            try {
                $uri = [Uri]$url
                $displayText = if ([string]::IsNullOrWhiteSpace($uri.PathAndQuery)) { "/" } else { $uri.PathAndQuery }
                if (-not [string]::IsNullOrWhiteSpace($uri.Fragment)) {
                    $displayText += $uri.Fragment
                }
            }
            catch {
                $displayText = $url
            }

            $safeHref = [System.Net.WebUtility]::HtmlEncode($url)
            $safeText = [System.Net.WebUtility]::HtmlEncode($displayText)
            return ('<a href="{0}" target="_blank" rel="noopener noreferrer">{1}</a>' -f $safeHref, $safeText)
        }
    )

    $HtmlContent = [regex]::Replace(
        $HtmlContent,
        '<td(?<attrs>[^>]*)>(?<value>[^<]*)</td>',
        {
            param($match)

            $attrs = [string]$match.Groups['attrs'].Value
            $value = [string]$match.Groups['value'].Value
            $trimmedValue = $value.Trim()

            if ([string]::IsNullOrWhiteSpace($trimmedValue)) {
                return $match.Value
            }

            $isNumericLike = $trimmedValue -match '^[\(\[]?\s*[+-]?\d[\d,]*(?:\.\d+)?(?:\s?(?:%|GB|MB|TB|KB|B|days?|hrs?|hours?|mins?|minutes?|secs?|seconds?))?(?:\s*\([^)]+\))?[\)\]]?$'

            if (-not $isNumericLike) {
                return $match.Value
            }

            if ($attrs -match 'class\s*=\s*"(?<classes>[^"]*)"') {
                $existingClasses = [string]$Matches['classes']
                if ($existingClasses -notmatch '(^|\s)num(\s|$)') {
                    $newClasses = ($existingClasses + ' num').Trim()
                    $attrs = [regex]::Replace($attrs, 'class\s*=\s*"[^"]*"', ('class="{0}"' -f $newClasses), 1)
                }
                return ('<td{0}>{1}</td>' -f $attrs, $value)
            }

            return ('<td class="num"{0}>{1}</td>' -f $attrs, $value)
        },
        [System.Text.RegularExpressions.RegexOptions]::IgnoreCase
    )

    $HtmlContent | Out-File -FilePath $ReportPath -Encoding UTF8 -Force
    return $HtmlContent
}