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.
Recommended (Level 2-3)
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
- Navigate to Power Platform Admin Center
- Select Licensing → Capacity
- Review current allocation:
- Power Apps per-user/per-app licenses
- Power Automate licenses
- Copilot Studio message capacity
- AI Builder credits
- 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
- Navigate to Azure Portal
- Go to Cost Management + Billing
- Select Cost Management → Cost analysis
- 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:
- Monthly usage data extracted (1st of month)
- Costs calculated per allocation model
- Charges posted to cost center ledger
- Reports sent to business unit managers
- 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
- License Tracking
- Power Platform Admin Center → Licensing
- Verify all licenses accounted for
-
Reconcile with procurement records
-
Azure Cost Management
- Verify resource tagging is complete
- Test cost queries by tag
-
Confirm data freshness
-
Budget Alerts
- Create test budget with low threshold
- Trigger test overspend
-
Verify email notification received
-
Chargeback Accuracy
- Compare chargeback to source costs
- Verify allocation percentages
- 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:
- Verify Cost Management Reader role assigned
- Check subscription is linked to billing account
- Allow 24-48 hours for initial data population
- Verify Azure Cost Management is enabled
Issue: Budget Alerts Not Triggering
Symptoms: Budget exceeded but no notification
Resolution:
- Verify email addresses are correct
- Check action group configuration
- Confirm threshold percentages
- Test with lower threshold
Issue: Cost Allocation Mismatch
Symptoms: Chargeback totals don't match Azure costs
Resolution:
- Check for untagged resources
- Verify tag key consistency
- Reconcile shared service allocations
- Review reserved capacity credits
Issue: License Cost Discrepancy
Symptoms: Reported license costs differ from invoices
Resolution:
- Reconcile with M365 Admin Center
- Check for trial licenses
- Verify pricing tier (E3 vs E5)
- Account for mid-month changes
Additional Resources
- Azure Cost Management
- Power Platform Licensing
- Azure Budgets
- Cost Allocation Rules
- Azure Advisor Cost Recommendations
Related Controls
| 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