Skip to content

Control 3.5: Cost Allocation and Budget Tracking

Overview

Control ID: 3.5 Control Name: Cost Allocation and Budget Tracking Regulatory Reference: SOX 404, GLBA 501(b), FINRA 4511, OCC 2011-12 Setup Time: 2-4 hours

Purpose

Cost Allocation and Budget Tracking provides comprehensive financial visibility into AI agent operations across the organization. This control establishes mechanisms for tracking license costs, consumption-based fees, development investments, and operational expenses associated with agent deployment and maintenance. For financial services organizations, this control supports SOX 404 financial controls, enables accurate technology cost allocation to business units, and ensures budget accountability for AI initiatives.


Prerequisites

Primary Owner Admin Role: Power Platform Admin Supporting Roles: None

Licensing Requirements

Component License Required
Power Platform Admin Center Included with Power Platform
Microsoft 365 Admin Center Microsoft 365 Enterprise
Azure Cost Management Azure subscription
Power BI for Reporting Power BI Pro or Premium
Microsoft Cost Management API Azure (included)

Permissions Required

Task Role/Permission
View Power Platform Licensing Power Platform Administrator
View Azure Costs Cost Management Reader
Configure Cost Allocation Billing Administrator
Create Budget Alerts Cost Management Contributor
Generate Cost Reports Power BI Pro + data access
Approve Budget Changes Finance Manager (business role)

Dependencies

  • [x] Control 3.1: Agent Inventory and Metadata Management
  • [x] Control 2.1: Managed Environments
  • [x] Control 2.2: Environment Groups and Tier Classification

Pre-Setup Checklist

  • [ ] Cost centers defined for AI agent allocation
  • [ ] Budget owners identified for each business unit
  • [ ] Chargeback/showback model approved
  • [ ] Azure billing structure configured
  • [ ] Power Platform licensing inventory complete

Governance Levels

Baseline (Level 1)

Track agent-related costs: licenses, hosting, development time; allocate to business units.

Monthly cost reports by agent/department; budget vs. actual tracking.

Regulated/High-Risk (Level 4)

Real-time cost visibility; cost alerts; financial governance.


Setup & Configuration

Step 1: Define Cost Categories and Structure

Cost Category Taxonomy:

Category Subcategory Cost Type Tracking Method
Licensing Power Platform Fixed Per-user/per-app
Microsoft 365 Fixed Per-user
Copilot Studio Consumption Message credits
AI Builder Consumption Credits
Infrastructure Azure Services Consumption Resource tagging
Storage Consumption GB/month
API Calls Consumption Transaction count
Development Labor Project Timesheet allocation
Consulting Project Invoice tracking
Training One-time Course fees
Operations Support Fixed FTE allocation
Maintenance Variable Incident costs
Monitoring Fixed Tool licensing

Step 2: Configure Power Platform Licensing Tracking

Portal Path: Power Platform Admin Center → Licensing → Capacity

  1. Navigate to Power Platform Admin Center
  2. Select LicensingCapacity
  3. Review current allocation:
  4. Power Apps per-user/per-app licenses
  5. Power Automate licenses
  6. Copilot Studio message capacity
  7. AI Builder credits
  8. Document license assignments by environment/agent

License Cost Mapping:

License Type Cost/Month Allocation Unit Tracking
Power Apps Premium ~$20/user User Entra ID groups
Power Apps per-app ~$5/app/user App App registration
Power Automate Premium ~$15/user User Flow assignments
Copilot Studio (25k Copilot Credits) ~$200 Copilot Credits Usage reports
AI Builder (1M credits) ~$500 Credits Consumption logs

Note

Pricing shown is approximate and may vary by agreement, region, and licensing program. Copilot Studio transitioned to the "Copilot Credits" model (September 2025). Consult your Microsoft licensing agreement for current pricing.

Step 3: Configure Azure Cost Management

Portal Path: Azure Portal → Cost Management + Billing → Cost Management

  1. Navigate to Azure Portal
  2. Go to Cost Management + Billing
  3. Select Cost ManagementCost analysis
  4. Create cost views for agent-related resources:

Recommended Tags for Agent Resources:

Tag Key Values Purpose
CostCenter Finance, HR, Operations, etc. Business unit allocation
AgentId Agent registry ID Link to inventory
Environment Dev, Test, Prod Environment allocation
Zone Zone1, Zone2, Zone3 Governance zone
Project Project code Project tracking

Step 4: Set Up Budget Alerts

Portal Path: Azure Cost Management → Budgets → + Add

Create budgets for each cost center:

Budget Name Scope Amount Alert Thresholds
AI-Platform-FY25 Subscription $100,000 50%, 75%, 90%, 100%
Dept-Finance-Agents Resource Group $25,000 75%, 90%, 100%
Dept-HR-Agents Resource Group $15,000 75%, 90%, 100%
Dev-Environment Resource Group $10,000 80%, 100%

Alert Actions:

  • Email budget owner at each threshold
  • Email finance team at 100%
  • Create incident ticket at 100%+ (optional)

Step 5: Build Cost Allocation Dashboard

Power BI Dashboard Components:

Section Visualizations Data Source
Executive Summary Total spend, trend, forecast Azure Cost Mgmt
By Business Unit Pie chart, table Cost center tags
By Agent Bar chart ranked by cost Agent registry + costs
By Category Stacked bar (license/infra/dev) Aggregated data
Budget vs. Actual Gauge, variance table Budget API
Trend Analysis Line chart (12 months) Historical data
Forecast Projected spend ML forecast

Step 6: Configure Chargeback/Showback Model

Allocation Methods:

Method Description Use Case
Direct 100% to single cost center Dedicated agent
Proportional Split by usage percentage Shared agent
Tiered Fixed base + variable usage Subscription model
Project-Based Allocate to project codes Development costs

Chargeback Process:

  1. Monthly usage data extracted (1st of month)
  2. Costs calculated per allocation model
  3. Charges posted to cost center ledger
  4. Reports sent to business unit managers
  5. Disputes resolved within 5 business days

Step 7: Implement Cost Optimization Recommendations

Portal Path: Azure Advisor → Cost Recommendations

Review and act on recommendations:

Recommendation Type Action Potential Savings
Unused licenses Reclaim and reassign 10-20%
Idle resources Shutdown or delete 5-15%
Right-sizing Downgrade oversized resources 10-25%
Reserved capacity Commit for discounts 15-40%
Orphaned agents Decommission Variable

PowerShell Configuration

# ============================================================
# Control 3.5: Cost Allocation and Budget Tracking
# PowerShell Configuration Script for FSI Organizations
# ============================================================

# Install required modules
Install-Module -Name Az.CostManagement -Force -AllowClobber
Install-Module -Name Az.Billing -Force -AllowClobber
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Force -AllowClobber

# Connect to services
Connect-AzAccount
Add-PowerAppsAccount

# ============================================================
# SECTION 1: Retrieve Power Platform Licensing Data
# ============================================================

function Get-PowerPlatformLicenseCosts {
    param(
        [string]$TenantId = (Get-AzContext).Tenant.Id
    )

    Write-Host "Retrieving Power Platform license inventory..." -ForegroundColor Cyan

    # Define license SKUs and costs
    $licenseCosts = @{
        "POWERAPPS_PER_USER" = @{ Name = "Power Apps per User"; MonthlyCost = 20 }
        "POWERAPPS_PER_APP" = @{ Name = "Power Apps per App"; MonthlyCost = 5 }
        "FLOW_PER_USER" = @{ Name = "Power Automate per User"; MonthlyCost = 15 }
        "POWER_VIRTUAL_AGENTS" = @{ Name = "Copilot Studio"; MonthlyCost = 200 }
        "AI_BUILDER" = @{ Name = "AI Builder"; MonthlyCost = 500 }
    }

    # Get environment summary
    $environments = Get-AdminPowerAppEnvironment

    $licenseSummary = @{
        RetrievedDate = Get-Date -Format "yyyy-MM-dd"
        EnvironmentCount = $environments.Count
        Environments = @()
    }

    foreach ($env in $environments) {
        $apps = Get-AdminPowerApp -EnvironmentName $env.EnvironmentName
        $flows = Get-AdminFlow -EnvironmentName $env.EnvironmentName

        $envData = @{
            Name = $env.DisplayName
            Type = $env.EnvironmentType
            AppCount = $apps.Count
            FlowCount = $flows.Count
            EstimatedMonthlyCost = 0  # Would need license assignment data
        }

        $licenseSummary.Environments += $envData
    }

    Write-Host "Found $($environments.Count) environments" -ForegroundColor Green
    return $licenseSummary
}

# ============================================================
# SECTION 2: Azure Cost Analysis
# ============================================================

function Get-AgentAzureCosts {
    param(
        [Parameter(Mandatory=$true)]
        [string]$ResourceGroupName,
        [int]$DaysBack = 30
    )

    Write-Host "Analyzing Azure costs for agent resources..." -ForegroundColor Cyan

    $startDate = (Get-Date).AddDays(-$DaysBack).ToString("yyyy-MM-dd")
    $endDate = (Get-Date).ToString("yyyy-MM-dd")

    # Query cost data
    $costQuery = @{
        type = "ActualCost"
        timeframe = "Custom"
        timePeriod = @{
            from = $startDate
            to = $endDate
        }
        dataset = @{
            granularity = "Daily"
            aggregation = @{
                totalCost = @{
                    name = "Cost"
                    function = "Sum"
                }
            }
            grouping = @(
                @{
                    type = "Dimension"
                    name = "ResourceType"
                }
            )
        }
    }

    try {
        $costs = Invoke-AzCostManagementQuery `
            -Scope "/subscriptions/$((Get-AzContext).Subscription.Id)/resourceGroups/$ResourceGroupName" `
            -QueryDefinition $costQuery

        Write-Host "Cost analysis complete" -ForegroundColor Green
        return $costs
    }
    catch {
        Write-Error "Failed to retrieve cost data: $_"
        return $null
    }
}

function Get-CostByTag {
    param(
        [Parameter(Mandatory=$true)]
        [string]$TagName,
        [string]$TagValue = "*",
        [int]$DaysBack = 30
    )

    Write-Host "Analyzing costs by tag: $TagName..." -ForegroundColor Cyan

    $startDate = (Get-Date).AddDays(-$DaysBack).ToString("yyyy-MM-dd")
    $endDate = (Get-Date).ToString("yyyy-MM-dd")

    $costQuery = @{
        type = "ActualCost"
        timeframe = "Custom"
        timePeriod = @{
            from = $startDate
            to = $endDate
        }
        dataset = @{
            granularity = "None"
            aggregation = @{
                totalCost = @{
                    name = "Cost"
                    function = "Sum"
                }
            }
            grouping = @(
                @{
                    type = "TagKey"
                    name = $TagName
                }
            )
        }
    }

    $costs = Invoke-AzCostManagementQuery `
        -Scope "/subscriptions/$((Get-AzContext).Subscription.Id)" `
        -QueryDefinition $costQuery

    return $costs
}

# ============================================================
# SECTION 3: Budget Management
# ============================================================

function New-AgentBudget {
    param(
        [Parameter(Mandatory=$true)]
        [string]$BudgetName,
        [Parameter(Mandatory=$true)]
        [decimal]$Amount,
        [Parameter(Mandatory=$true)]
        [string]$Scope,
        [string[]]$NotificationEmails,
        [int[]]$ThresholdPercentages = @(50, 75, 90, 100)
    )

    Write-Host "Creating budget: $BudgetName ($Amount)..." -ForegroundColor Cyan

    $startDate = (Get-Date -Day 1).ToString("yyyy-MM-dd")
    $endDate = (Get-Date).AddYears(1).ToString("yyyy-MM-dd")

    # Build notification rules
    $notifications = @{}
    foreach ($threshold in $ThresholdPercentages) {
        $notifications["Alert$threshold"] = @{
            enabled = $true
            operator = "GreaterThan"
            threshold = $threshold
            contactEmails = $NotificationEmails
            thresholdType = "Actual"
        }
    }

    $budgetParams = @{
        Name = $BudgetName
        Scope = $Scope
        Amount = $Amount
        TimeGrain = "Monthly"
        TimePeriod = @{
            StartDate = $startDate
            EndDate = $endDate
        }
        Category = "Cost"
        Notification = $notifications
    }

    try {
        New-AzConsumptionBudget @budgetParams
        Write-Host "Budget created successfully" -ForegroundColor Green
    }
    catch {
        Write-Error "Failed to create budget: $_"
    }
}

function Get-BudgetStatus {
    param(
        [string]$Scope = "/subscriptions/$((Get-AzContext).Subscription.Id)"
    )

    Write-Host "Retrieving budget status..." -ForegroundColor Cyan

    $budgets = Get-AzConsumptionBudget -Scope $Scope

    $budgetStatus = @()

    foreach ($budget in $budgets) {
        $currentSpend = $budget.CurrentSpend.Amount
        $budgetAmount = $budget.Amount
        $percentUsed = [math]::Round(($currentSpend / $budgetAmount) * 100, 1)

        $status = @{
            Name = $budget.Name
            BudgetAmount = $budgetAmount
            CurrentSpend = $currentSpend
            PercentUsed = $percentUsed
            Remaining = $budgetAmount - $currentSpend
            Status = if ($percentUsed -ge 100) { "Exceeded" }
                     elseif ($percentUsed -ge 90) { "Critical" }
                     elseif ($percentUsed -ge 75) { "Warning" }
                     else { "Normal" }
        }

        $budgetStatus += [PSCustomObject]$status
    }

    Write-Host "Budget Status Summary:" -ForegroundColor Green
    $budgetStatus | Format-Table -AutoSize

    return $budgetStatus
}

# ============================================================
# SECTION 4: Cost Allocation Report
# ============================================================

function New-CostAllocationReport {
    param(
        [int]$Month = (Get-Date).Month,
        [int]$Year = (Get-Date).Year,
        [string]$OutputPath = ".\CostAllocationReport.html"
    )

    Write-Host "Generating cost allocation report for $Month/$Year..." -ForegroundColor Cyan

    # Sample cost data structure (in production, query actual sources)
    $costData = @{
        ReportPeriod = "$Month/$Year"
        GeneratedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        TotalCost = 45000
        Categories = @(
            @{ Name = "Licensing"; Amount = 15000; Percentage = 33 },
            @{ Name = "Infrastructure"; Amount = 18000; Percentage = 40 },
            @{ Name = "Development"; Amount = 8000; Percentage = 18 },
            @{ Name = "Operations"; Amount = 4000; Percentage = 9 }
        )
        ByBusinessUnit = @(
            @{ Unit = "Finance"; Agents = 5; Cost = 12000 },
            @{ Unit = "Operations"; Agents = 8; Cost = 18000 },
            @{ Unit = "HR"; Agents = 3; Cost = 6000 },
            @{ Unit = "Customer Service"; Agents = 4; Cost = 9000 }
        )
        TopAgentsByCost = @(
            @{ Name = "Account Inquiry Bot"; Cost = 5500; Tier = "Tier 3" },
            @{ Name = "HR Benefits Assistant"; Cost = 4200; Tier = "Tier 2" },
            @{ Name = "IT Helpdesk Bot"; Cost = 3800; Tier = "Tier 2" },
            @{ Name = "Expense Report Helper"; Cost = 2900; Tier = "Tier 1" },
            @{ Name = "Compliance Q&A Bot"; Cost = 2500; Tier = "Tier 3" }
        )
    }

    $html = @"
<!DOCTYPE html>
<html>
<head>
    <title>AI Agent Cost Allocation Report - $($costData.ReportPeriod)</title>
    <style>
        body { font-family: 'Segoe UI', Arial, sans-serif; margin: 40px; background: #f8f9fa; }
        .container { max-width: 1100px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        h1 { color: #0078D4; border-bottom: 3px solid #0078D4; padding-bottom: 15px; }
        h2 { color: #333; margin-top: 30px; }
        .metric-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin: 20px 0; }
        .metric-card { background: linear-gradient(135deg, #0078D4, #00BCF2); color: white; padding: 20px; border-radius: 8px; text-align: center; }
        .metric-value { font-size: 28px; font-weight: bold; }
        .metric-label { font-size: 14px; opacity: 0.9; }
        table { width: 100%; border-collapse: collapse; margin: 20px 0; }
        th { background: #0078D4; color: white; padding: 12px; text-align: left; }
        td { border: 1px solid #ddd; padding: 10px; }
        tr:nth-child(even) { background: #f9f9f9; }
        .category-bar { height: 20px; border-radius: 4px; background: #0078D4; }
        .warning { color: #856404; background: #FFF3CD; padding: 10px; border-radius: 4px; }
        .footer { text-align: center; color: #666; margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; }
    </style>
</head>
<body>
    <div class="container">
        <h1>💰 AI Agent Cost Allocation Report</h1>
        <p><strong>Report Period:</strong> $($costData.ReportPeriod) | <strong>Generated:</strong> $($costData.GeneratedDate)</p>

        <div class="metric-row">
            <div class="metric-card">
                <div class="metric-value">$([string]::Format("{0:C0}", $costData.TotalCost))</div>
                <div class="metric-label">Total Monthly Cost</div>
            </div>
            <div class="metric-card">
                <div class="metric-value">$($costData.ByBusinessUnit.Count)</div>
                <div class="metric-label">Business Units</div>
            </div>
            <div class="metric-card">
                <div class="metric-value">$(($costData.ByBusinessUnit | ForEach-Object { $_.Agents } | Measure-Object -Sum).Sum)</div>
                <div class="metric-label">Active Agents</div>
            </div>
            <div class="metric-card">
                <div class="metric-value">$([math]::Round($costData.TotalCost / 20, 0))</div>
                <div class="metric-label">Avg Cost/Agent</div>
            </div>
        </div>

        <h2>Cost by Category</h2>
        <table>
            <tr><th>Category</th><th>Amount</th><th>%</th><th>Distribution</th></tr>
            $($costData.Categories | ForEach-Object {
                "<tr>
                    <td>$($_.Name)</td>
                    <td>$([string]::Format('{0:C0}', $_.Amount))</td>
                    <td>$($_.Percentage)%</td>
                    <td><div class='category-bar' style='width: $($_.Percentage * 2)px'></div></td>
                </tr>"
            })
        </table>

        <h2>Cost by Business Unit</h2>
        <table>
            <tr><th>Business Unit</th><th>Active Agents</th><th>Monthly Cost</th><th>Cost/Agent</th></tr>
            $($costData.ByBusinessUnit | ForEach-Object {
                $costPerAgent = [math]::Round($_.Cost / $_.Agents, 0)
                "<tr>
                    <td>$($_.Unit)</td>
                    <td>$($_.Agents)</td>
                    <td>$([string]::Format('{0:C0}', $_.Cost))</td>
                    <td>$([string]::Format('{0:C0}', $costPerAgent))</td>
                </tr>"
            })
        </table>

        <h2>Top 5 Agents by Cost</h2>
        <table>
            <tr><th>Agent Name</th><th>Tier</th><th>Monthly Cost</th></tr>
            $($costData.TopAgentsByCost | ForEach-Object {
                "<tr>
                    <td>$($_.Name)</td>
                    <td>$($_.Tier)</td>
                    <td>$([string]::Format('{0:C0}', $_.Cost))</td>
                </tr>"
            })
        </table>

        <h2>Cost Optimization Recommendations</h2>
        <div class="warning">
            <strong>Review Recommended:</strong>
            <ul>
                <li>3 agents with <5 sessions/month identified for potential decommissioning</li>
                <li>2 licenses unassigned - consider reallocation</li>
                <li>Dev environment costs up 15% - review for cleanup</li>
            </ul>
        </div>

        <div class="footer">
            <p>Generated by FSI-AgentGov Cost Tracking System</p>
            <p>For questions, contact: finance-aiops@company.com</p>
        </div>
    </div>
</body>
</html>
"@

    $html | Out-File -FilePath $OutputPath -Encoding UTF8
    Write-Host "Report generated: $OutputPath" -ForegroundColor Green

    return $OutputPath
}

# ============================================================
# SECTION 5: Cost Anomaly Detection
# ============================================================

function Find-CostAnomalies {
    param(
        [int]$MonthsToAnalyze = 6,
        [double]$ThresholdMultiplier = 2.0
    )

    Write-Host "Analyzing cost patterns for anomalies..." -ForegroundColor Cyan

    # Sample historical data (in production, query actual cost history)
    $historicalCosts = @(
        @{ Month = "Jul"; Cost = 42000 },
        @{ Month = "Aug"; Cost = 43500 },
        @{ Month = "Sep"; Cost = 44200 },
        @{ Month = "Oct"; Cost = 43800 },
        @{ Month = "Nov"; Cost = 45000 },
        @{ Month = "Dec"; Cost = 58000 }  # Anomaly
    )

    # Calculate baseline
    $costs = $historicalCosts | ForEach-Object { $_.Cost }
    $mean = ($costs | Measure-Object -Average).Average
    $stdDev = Get-StandardDeviation -Values $costs
    $upperThreshold = $mean + ($ThresholdMultiplier * $stdDev)
    $lowerThreshold = $mean - ($ThresholdMultiplier * $stdDev)

    Write-Host "Baseline: Mean = $([math]::Round($mean, 0)), StdDev = $([math]::Round($stdDev, 0))" -ForegroundColor Gray
    Write-Host "Thresholds: Lower = $([math]::Round($lowerThreshold, 0)), Upper = $([math]::Round($upperThreshold, 0))" -ForegroundColor Gray

    $anomalies = $historicalCosts | Where-Object {
        $_.Cost -gt $upperThreshold -or $_.Cost -lt $lowerThreshold
    }

    if ($anomalies.Count -gt 0) {
        Write-Host "`n⚠️ Cost Anomalies Detected:" -ForegroundColor Yellow
        $anomalies | ForEach-Object {
            $deviation = [math]::Round((($_.Cost - $mean) / $stdDev), 1)
            Write-Host "  $($_.Month): $($_.Cost) ($deviation σ from mean)" -ForegroundColor Red
        }
    }
    else {
        Write-Host "✅ No cost anomalies detected" -ForegroundColor Green
    }

    return $anomalies
}

function Get-StandardDeviation {
    param([array]$Values)
    $mean = ($Values | Measure-Object -Average).Average
    $squaredDiffs = $Values | ForEach-Object { [Math]::Pow($_ - $mean, 2) }
    $variance = ($squaredDiffs | Measure-Object -Average).Average
    return [Math]::Sqrt($variance)
}

# ============================================================
# SECTION 6: Chargeback Processing
# ============================================================

function Process-MonthlyChargeback {
    param(
        [int]$Month = (Get-Date).AddMonths(-1).Month,
        [int]$Year = (Get-Date).AddMonths(-1).Year
    )

    Write-Host "Processing chargeback for $Month/$Year..." -ForegroundColor Cyan

    # Sample allocation data
    $chargebackRecords = @(
        @{ CostCenter = "CC-FIN-001"; Department = "Finance"; Amount = 12000; AgentCount = 5 },
        @{ CostCenter = "CC-OPS-002"; Department = "Operations"; Amount = 18000; AgentCount = 8 },
        @{ CostCenter = "CC-HR-003"; Department = "HR"; Amount = 6000; AgentCount = 3 },
        @{ CostCenter = "CC-CS-004"; Department = "Customer Service"; Amount = 9000; AgentCount = 4 }
    )

    Write-Host "`nChargeback Summary for $Month/$Year:" -ForegroundColor Green
    Write-Host "======================================" -ForegroundColor Green

    $total = 0
    foreach ($record in $chargebackRecords) {
        Write-Host "$($record.CostCenter) | $($record.Department): $([string]::Format('{0:C0}', $record.Amount)) ($($record.AgentCount) agents)"
        $total += $record.Amount
    }

    Write-Host "--------------------------------------"
    Write-Host "TOTAL: $([string]::Format('{0:C0}', $total))" -ForegroundColor Cyan

    # Export for ERP integration
    $chargebackRecords | Export-Csv -Path ".\Chargeback-$Year-$Month.csv" -NoTypeInformation
    Write-Host "`nChargeback file exported for ERP import" -ForegroundColor Green

    return $chargebackRecords
}

# ============================================================
# EXAMPLE USAGE
# ============================================================

Write-Host "=== Control 3.5: Cost Allocation and Budget Tracking ===" -ForegroundColor Magenta

# Get Power Platform license costs
# Get-PowerPlatformLicenseCosts

# Get Azure costs for agent resources
# Get-AgentAzureCosts -ResourceGroupName "rg-ai-agents-prod" -DaysBack 30

# Create a budget
# New-AgentBudget -BudgetName "AI-Agents-Q1" -Amount 50000 -Scope "/subscriptions/xxx/resourceGroups/rg-ai-agents" -NotificationEmails @("finance@company.com")

# Check budget status
# Get-BudgetStatus

# Generate cost allocation report
# New-CostAllocationReport -Month 12 -Year 2024

# Find cost anomalies
# Find-CostAnomalies

# Process monthly chargeback
# Process-MonthlyChargeback -Month 12 -Year 2024

Write-Host "`nConfiguration script ready. Uncomment and run desired functions." -ForegroundColor Green

Financial Sector Considerations

Regulatory Requirements

Regulation Requirement Implementation
SOX 404 IT cost controls documentation Document cost tracking as financial control
GLBA 501(b) Safeguard investment tracking Track security-related agent costs
FINRA 4511 Financial records retention Retain cost records for 6+ years
OCC 2011-12 Third-party cost visibility Track vendor costs separately
Internal Audit Cost allocation accuracy Implement reconciliation process

Zone-Specific Configuration

Zone Cost Tracking Granularity Budget Control Approval
Zone 1 (Personal Productivity) Aggregate by department Soft limits Team Lead
Zone 2 (Team Collaboration) By agent Hard limits Manager
Zone 3 (Enterprise Managed) Detailed breakout Real-time enforcement Director/VP

FSI Example: Enterprise Agent Cost Structure

Agent: Customer Account Inquiry Bot (Tier 3)
Department: Customer Service
Cost Center: CC-CS-004

Monthly Cost Breakdown:
├── Licensing
│   ├── Copilot Studio messages: $800 (40,000 msgs)
│   ├── AI Builder credits: $200
│   └── Power Apps per-app: $50 (10 users)
├── Infrastructure
│   ├── Azure OpenAI: $1,500
│   ├── Azure Storage: $50
│   └── Application Insights: $100
├── Operations
│   ├── Support (0.1 FTE): $800
│   └── Monitoring tools: $100
└── TOTAL: $3,600/month

ROI Analysis:
├── Calls deflected: 8,000/month
├── Cost per call (human): $5.00
├── Savings: $40,000/month
└── Net Benefit: $36,400/month

Verification & Testing

Verification Steps

  1. License Tracking
  2. Power Platform Admin Center → Licensing
  3. Verify all licenses accounted for
  4. Reconcile with procurement records

  5. Azure Cost Management

  6. Verify resource tagging is complete
  7. Test cost queries by tag
  8. Confirm data freshness

  9. Budget Alerts

  10. Create test budget with low threshold
  11. Trigger test overspend
  12. Verify email notification received

  13. Chargeback Accuracy

  14. Compare chargeback to source costs
  15. Verify allocation percentages
  16. Confirm cost center mappings

Compliance Checklist

Item Required For Status
Monthly cost allocation reports SOX 404
Budget alerts configured Financial governance
Cost center tagging complete Accurate allocation
Chargeback process documented Internal audit
Cost records retained 6+ years FINRA 4511
Quarterly cost review meetings Best practice
Cost optimization reviews Efficiency

Troubleshooting & Validation

Issue: Azure Cost Data Not Appearing

Symptoms: Cost Management shows no data

Resolution:

  1. Verify Cost Management Reader role assigned
  2. Check subscription is linked to billing account
  3. Allow 24-48 hours for initial data population
  4. Verify Azure Cost Management is enabled

Issue: Budget Alerts Not Triggering

Symptoms: Budget exceeded but no notification

Resolution:

  1. Verify email addresses are correct
  2. Check action group configuration
  3. Confirm threshold percentages
  4. Test with lower threshold

Issue: Cost Allocation Mismatch

Symptoms: Chargeback totals don't match Azure costs

Resolution:

  1. Check for untagged resources
  2. Verify tag key consistency
  3. Reconcile shared service allocations
  4. Review reserved capacity credits

Issue: License Cost Discrepancy

Symptoms: Reported license costs differ from invoices

Resolution:

  1. Reconcile with M365 Admin Center
  2. Check for trial licenses
  3. Verify pricing tier (E3 vs E5)
  4. Account for mid-month changes

Additional Resources

Control Relationship
3.1 Agent Inventory Links costs to agent metadata
3.3 Compliance Reporting Includes cost metrics in reports
3.6 Orphaned Agent Detection Identifies cost reduction opportunities
2.1 Managed Environments Environment-based cost allocation
2.7 Vendor Risk Management Third-party cost tracking

Support & Questions

For implementation support or questions about this control, contact:

  • AI Governance Lead (governance direction)
  • Compliance Officer (regulatory requirements)
  • Technical Implementation Team (platform setup)

Updated: Dec 2025
Version: v1.0 Beta (Dec 2025)
UI Verification Status: ❌ Needs verification