src/Private/New-ReclaimReportCsv.ps1

function New-ReclaimReportCsv {
    <#
    .SYNOPSIS
        Exports the named per-account remediation list to CSV. FULL mode only.
    .DESCRIPTION
        This is the paid deliverable: the exact accounts to deprovision, one row per account,
        with the licenses to reclaim and the monthly dollars each is wasting. Refuses to write
        in Free mode so the gate cannot be bypassed via the CSV path.
    .OUTPUTS
        The path written, or $null if the report is not unlocked.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [object] $Report,
        [Parameter(Mandatory)] [string] $Path
    )

    if ($Report.Mode -ne 'Full') {
        Write-Warning 'CSV export of the named account list requires an unlocked (Full) report. Run Unlock-OpteraLicenseReclaim.'
        return $null
    }

    # CSV formula-injection guard: a directory value beginning with =, +, -, @ (or a leading
    # tab/CR that Excel strips before re-evaluating) is treated as a formula when the file is
    # opened in a spreadsheet. Prefix such values with an apostrophe so they render as text.
    # The named remediation list is the whole point of this export, so it must be safe to open.
    function _csvSafe([object]$v) {
        $s = [string]$v
        if ($s -and $s[0] -in '=', '+', '-', '@', "`t", "`r") { return "'$s" }
        return $s
    }

    $rows = $Report.Reclaimable | Sort-Object MonthlyWasteUsd -Descending | ForEach-Object {
        [pscustomobject]@{
            DisplayName       = _csvSafe $_.DisplayName
            UserPrincipalName = _csvSafe $_.UserPrincipalName
            SamAccountName    = _csvSafe $_.SamAccountName
            Domain            = _csvSafe $_.Domain
            Reason            = _csvSafe $_.Reason
            DaysSinceLogon    = $_.DaysSinceLogon
            OrgUnit           = _csvSafe $_.OrgUnit
            Licenses          = _csvSafe (($_.Skus | ForEach-Object { $_.Name }) -join '; ')
            MonthlyWasteUsd   = $_.MonthlyWasteUsd
            AnnualWasteUsd    = [math]::Round($_.MonthlyWasteUsd * 12, 2)
            MatchedBy         = _csvSafe $_.MatchedBy
            DistinguishedName = _csvSafe $_.DistinguishedName
        }
    }

    $dir = Split-Path -Parent $Path
    if ($dir -and -not (Test-Path -LiteralPath $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
    $rows | Export-Csv -LiteralPath $Path -NoTypeInformation -Encoding UTF8
    return $Path
}