mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
530 lines
24 KiB
PowerShell
530 lines
24 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Retrieves GitHub Copilot usage metrics per user for an organization.
|
|
|
|
.DESCRIPTION
|
|
This script calls the GitHub REST API to get Copilot metrics for an organization,
|
|
showing usage per user to help identify who is actively using their premium seats.
|
|
|
|
.PARAMETER Organization
|
|
The GitHub organization name.
|
|
|
|
.PARAMETER Token
|
|
GitHub Personal Access Token with 'copilot', 'manage_billing:copilot', or 'read:org' scope.
|
|
If not provided, will attempt to use GITHUB_TOKEN environment variable.
|
|
|
|
.PARAMETER Days
|
|
Number of days to look back (default: 28, max: 28).
|
|
|
|
.PARAMETER ExportToExcel
|
|
Optional path to export results to Excel file (e.g., "copilot-usage.xlsx").
|
|
|
|
.PARAMETER IncludeUserSeats
|
|
Include individual user seat information (who has access and when they last used it).
|
|
|
|
.EXAMPLE
|
|
.\Get-CopilotUsage.ps1 -Organization "myorg" -Token "ghp_xxxxx"
|
|
|
|
.EXAMPLE
|
|
.\Get-CopilotUsage.ps1 -Organization "myorg" -Days 7 -ExportToExcel "copilot-usage.xlsx"
|
|
|
|
.EXAMPLE
|
|
.\Get-CopilotUsage.ps1 -Organization "myorg" -IncludeUserSeats -ExportToExcel "copilot-usage.xlsx"
|
|
|
|
.NOTES
|
|
API Documentation: https://docs.github.com/en/rest/copilot/copilot-metrics
|
|
Required Token Scopes: 'copilot', 'manage_billing:copilot', or 'read:org'
|
|
This script requires the ImportExcel module. Install it with: Install-Module -Name ImportExcel
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Organization,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$Token,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateRange(1, 28)]
|
|
[int]$Days = 28,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$ExportToExcel,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$IncludeUserSeats
|
|
)
|
|
|
|
# Check if ImportExcel module is available when export is requested
|
|
if (-not [string]::IsNullOrEmpty($ExportToExcel)) {
|
|
if (-not (Get-Module -ListAvailable -Name ImportExcel)) {
|
|
Write-Warning "ImportExcel module is not installed. Installing it now..."
|
|
try {
|
|
Install-Module -Name ImportExcel -Scope CurrentUser -Force -AllowClobber
|
|
Write-Host "ImportExcel module installed successfully." -ForegroundColor Green
|
|
} catch {
|
|
Write-Error "Failed to install ImportExcel module. Please install it manually: Install-Module -Name ImportExcel"
|
|
Write-Host "Continuing without Excel export..." -ForegroundColor Yellow
|
|
$ExportToExcel = ""
|
|
}
|
|
}
|
|
if (-not [string]::IsNullOrEmpty($ExportToExcel)) {
|
|
Import-Module ImportExcel
|
|
}
|
|
}
|
|
|
|
# Use environment variable if token not provided
|
|
if ([string]::IsNullOrEmpty($Token)) {
|
|
$Token = $env:GITHUB_TOKEN
|
|
if ([string]::IsNullOrEmpty($Token)) {
|
|
Write-Error "GitHub token not provided. Use -Token parameter or set GITHUB_TOKEN environment variable."
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# API endpoint
|
|
$apiUrl = "https://api.github.com/orgs/$Organization/copilot/metrics"
|
|
|
|
# Headers for authentication
|
|
$headers = @{
|
|
"Accept" = "application/vnd.github+json"
|
|
"Authorization" = "Bearer $Token"
|
|
"X-GitHub-Api-Version" = "2022-11-28"
|
|
}
|
|
|
|
Write-Host "Fetching Copilot usage metrics for organization: $Organization" -ForegroundColor Cyan
|
|
Write-Host "Time period: Last $Days days" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
# Variables to store data
|
|
$dailySummary = @()
|
|
$languageSummary = @()
|
|
$editorSummary = @()
|
|
$overallSummary = $null
|
|
$userSeats = @()
|
|
|
|
try {
|
|
# Calculate date range
|
|
$since = (Get-Date).AddDays(-$Days).ToString("yyyy-MM-dd")
|
|
$until = (Get-Date).ToString("yyyy-MM-dd")
|
|
|
|
# Add query parameters
|
|
$uri = "$apiUrl`?since=$since&until=$until"
|
|
|
|
# Make API request
|
|
$response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
|
|
|
|
if ($null -eq $response -or $response.Count -eq 0) {
|
|
Write-Warning "No usage data found for the specified period."
|
|
exit 0
|
|
}
|
|
|
|
# Process and display results
|
|
$userMetrics = @()
|
|
|
|
foreach ($dayMetric in $response) {
|
|
$date = $dayMetric.date
|
|
|
|
if ($null -ne $dayMetric.copilot_ide_code_completions) {
|
|
foreach ($editor in $dayMetric.copilot_ide_code_completions.editors) {
|
|
foreach ($model in $editor.models) {
|
|
foreach ($language in $model.languages) {
|
|
$userMetrics += [PSCustomObject]@{
|
|
Date = $date
|
|
Editor = $editor.name
|
|
Model = $model.name
|
|
Language = $language.name
|
|
TotalEngagedUsers = $language.total_engaged_users
|
|
SuggestionsCount = $language.total_code_suggestions
|
|
AcceptancesCount = $language.total_code_acceptances
|
|
LinesAccepted = $language.total_code_lines_accepted
|
|
LinesSuggested = $language.total_code_lines_suggested
|
|
ActiveUsers = $language.total_engaged_users
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Aggregate by user activity
|
|
Write-Host "=== COPILOT USAGE SUMMARY ===" -ForegroundColor Green
|
|
Write-Host ""
|
|
|
|
if ($userMetrics.Count -eq 0) {
|
|
Write-Warning "No detailed metrics available for this period."
|
|
} else {
|
|
# Group by date and calculate totals
|
|
$dailySummary = $userMetrics | Group-Object Date | ForEach-Object {
|
|
$dayData = $_.Group
|
|
[PSCustomObject]@{
|
|
Date = $_.Name
|
|
TotalEngagedUsers = ($dayData | Measure-Object -Property TotalEngagedUsers -Maximum).Maximum
|
|
TotalSuggestions = ($dayData | Measure-Object -Property SuggestionsCount -Sum).Sum
|
|
TotalAcceptances = ($dayData | Measure-Object -Property AcceptancesCount -Sum).Sum
|
|
TotalLinesAccepted = ($dayData | Measure-Object -Property LinesAccepted -Sum).Sum
|
|
AcceptanceRate = if (($dayData | Measure-Object -Property SuggestionsCount -Sum).Sum -gt 0) {
|
|
[math]::Round((($dayData | Measure-Object -Property AcceptancesCount -Sum).Sum /
|
|
($dayData | Measure-Object -Property SuggestionsCount -Sum).Sum) * 100, 2)
|
|
} else { 0 }
|
|
}
|
|
} | Sort-Object Date -Descending
|
|
|
|
# Display daily summary
|
|
Write-Host "Daily Summary:" -ForegroundColor Yellow
|
|
$dailySummary | Format-Table -AutoSize
|
|
|
|
# Calculate overall statistics
|
|
$totalUsers = ($dailySummary | Measure-Object -Property TotalEngagedUsers -Maximum).Maximum
|
|
$totalSuggestions = ($dailySummary | Measure-Object -Property TotalSuggestions -Sum).Sum
|
|
$totalAcceptances = ($dailySummary | Measure-Object -Property TotalAcceptances -Sum).Sum
|
|
$overallAcceptanceRate = if ($totalSuggestions -gt 0) {
|
|
[math]::Round(($totalAcceptances / $totalSuggestions) * 100, 2)
|
|
} else { 0 }
|
|
|
|
Write-Host ""
|
|
Write-Host "=== OVERALL STATISTICS ===" -ForegroundColor Green
|
|
Write-Host "Peak Engaged Users: $totalUsers" -ForegroundColor White
|
|
Write-Host "Total Suggestions: $totalSuggestions" -ForegroundColor White
|
|
Write-Host "Total Acceptances: $totalAcceptances" -ForegroundColor White
|
|
Write-Host "Overall Acceptance Rate: $overallAcceptanceRate%" -ForegroundColor White
|
|
Write-Host ""
|
|
|
|
# Language breakdown
|
|
$languageSummary = $userMetrics | Group-Object Language | ForEach-Object {
|
|
$langData = $_.Group
|
|
[PSCustomObject]@{
|
|
Language = $_.Name
|
|
TotalSuggestions = ($langData | Measure-Object -Property SuggestionsCount -Sum).Sum
|
|
TotalAcceptances = ($langData | Measure-Object -Property AcceptancesCount -Sum).Sum
|
|
AcceptanceRate = if (($langData | Measure-Object -Property SuggestionsCount -Sum).Sum -gt 0) {
|
|
[math]::Round((($langData | Measure-Object -Property AcceptancesCount -Sum).Sum /
|
|
($langData | Measure-Object -Property SuggestionsCount -Sum).Sum) * 100, 2)
|
|
} else { 0 }
|
|
}
|
|
} | Sort-Object TotalAcceptances -Descending
|
|
|
|
Write-Host "Language Breakdown:" -ForegroundColor Yellow
|
|
$languageSummary | Format-Table -AutoSize
|
|
|
|
# Editor breakdown
|
|
$editorSummary = $userMetrics | Group-Object Editor | ForEach-Object {
|
|
$editorData = $_.Group
|
|
[PSCustomObject]@{
|
|
Editor = $_.Name
|
|
TotalSuggestions = ($editorData | Measure-Object -Property SuggestionsCount -Sum).Sum
|
|
TotalAcceptances = ($editorData | Measure-Object -Property AcceptancesCount -Sum).Sum
|
|
}
|
|
} | Sort-Object TotalAcceptances -Descending
|
|
|
|
Write-Host "Editor Breakdown:" -ForegroundColor Yellow
|
|
$editorSummary | Format-Table -AutoSize
|
|
|
|
# Create overall summary object for Excel
|
|
$overallSummary = [PSCustomObject]@{
|
|
Organization = $Organization
|
|
DateRange = "$since to $until"
|
|
PeakEngagedUsers = $totalUsers
|
|
TotalSuggestions = $totalSuggestions
|
|
TotalAcceptances = $totalAcceptances
|
|
OverallAcceptanceRate = "$overallAcceptanceRate%"
|
|
ReportGeneratedDate = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
|
|
}
|
|
}
|
|
|
|
# Fetch individual user seat information if requested
|
|
if ($IncludeUserSeats) {
|
|
Write-Host ""
|
|
Write-Host "=== FETCHING USER SEAT INFORMATION ===" -ForegroundColor Green
|
|
Write-Host ""
|
|
|
|
try {
|
|
# First, get the seat assignments
|
|
$seatsUrl = "https://api.github.com/orgs/$Organization/copilot/billing/seats"
|
|
$page = 1
|
|
$perPage = 100
|
|
$allSeats = @()
|
|
|
|
do {
|
|
$seatsUri = "$seatsUrl`?per_page=$perPage&page=$page"
|
|
$seatsResponse = Invoke-RestMethod -Uri $seatsUri -Headers $headers -Method Get
|
|
|
|
if ($null -ne $seatsResponse.seats) {
|
|
$allSeats += $seatsResponse.seats
|
|
}
|
|
|
|
$page++
|
|
} while ($seatsResponse.seats.Count -eq $perPage)
|
|
|
|
Write-Host "Found $($allSeats.Count) user seats" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host "NOTE: GitHub does not provide per-user 'credit usage' via API." -ForegroundColor Yellow
|
|
Write-Host "Credit calculation is based on billing model: 1 seat = 300 credits/month" -ForegroundColor Yellow
|
|
Write-Host "'Wasting credits' means: seat assigned but user inactive >30 days" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
|
|
# Calculate credits consumed per user
|
|
# GitHub Copilot Business/Enterprise charges per seat regardless of usage
|
|
# If a user has a seat assigned, they consume the full month's credits
|
|
# The "last_activity_at" tells us if they're actually using it
|
|
$creditsPerMonth = 300
|
|
$daysInMonth = [DateTime]::DaysInMonth((Get-Date).Year, (Get-Date).Month)
|
|
$currentDay = (Get-Date).Day
|
|
|
|
# Calculate how many days have passed in the current month
|
|
$daysElapsedInMonth = $currentDay
|
|
|
|
if ($allSeats.Count -eq 0) {
|
|
Write-Warning "No user seats found."
|
|
} else {
|
|
$userSeats = $allSeats | ForEach-Object {
|
|
$username = $_.assignee.login
|
|
|
|
$lastActivityDate = if ($_.last_activity_at) {
|
|
try {
|
|
# Try parsing as DateTime - handles multiple formats
|
|
if ($_.last_activity_at -is [DateTime]) {
|
|
$_.last_activity_at
|
|
} else {
|
|
[DateTime]::Parse($_.last_activity_at, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::None)
|
|
}
|
|
} catch {
|
|
# Fallback: try different parsing methods
|
|
try {
|
|
[DateTime]::ParseExact($_.last_activity_at, "MM/dd/yyyy HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture)
|
|
} catch {
|
|
try {
|
|
# ISO 8601 format
|
|
[DateTime]::Parse($_.last_activity_at)
|
|
} catch {
|
|
Write-Verbose "Could not parse date: $($_.last_activity_at) for user $username"
|
|
$null
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
$null
|
|
}
|
|
|
|
$daysSinceLastActivity = if ($lastActivityDate) {
|
|
[math]::Round(((Get-Date) - $lastActivityDate).TotalDays)
|
|
} else {
|
|
$null
|
|
}
|
|
|
|
$isActive = if ($daysSinceLastActivity -ne $null) {
|
|
$daysSinceLastActivity -le 30
|
|
} else {
|
|
$false
|
|
}
|
|
|
|
$assignedDate = if ($_.created_at) {
|
|
try {
|
|
if ($_.created_at -is [DateTime]) {
|
|
$_.created_at
|
|
} else {
|
|
$parsedDate = [DateTime]::Parse($_.created_at, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::None)
|
|
$parsedDate
|
|
}
|
|
} catch {
|
|
try {
|
|
[DateTime]::ParseExact($_.created_at, "MM/dd/yyyy HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture)
|
|
} catch {
|
|
$null
|
|
}
|
|
}
|
|
} else {
|
|
$null
|
|
}
|
|
|
|
# Calculate credits consumed
|
|
# GitHub Copilot billing model: Charges per seat per month
|
|
# Once a seat is assigned, the FULL monthly cost applies
|
|
# Credits don't depend on usage - they're consumed just by having the seat
|
|
|
|
# Check if the seat is currently assigned (not pending cancellation)
|
|
$isPendingCancellation = ![string]::IsNullOrEmpty($_.pending_cancellation_date)
|
|
|
|
if ($isPendingCancellation) {
|
|
# Seat is being cancelled - no credits for full month
|
|
$creditsConsumed = 0
|
|
} elseif ($assignedDate -and $assignedDate.Year -eq (Get-Date).Year -and $assignedDate.Month -eq (Get-Date).Month) {
|
|
# Assigned THIS month - pro-rate based on days from assignment to end of month
|
|
$daysAssignedThisMonth = $currentDay - $assignedDate.Day + 1
|
|
$creditsConsumed = [math]::Round(($daysAssignedThisMonth / $daysInMonth) * $creditsPerMonth, 2)
|
|
} else {
|
|
# Assigned before this month - FULL month charge
|
|
$creditsConsumed = $creditsPerMonth
|
|
}
|
|
|
|
$creditsRemaining = [math]::Round($creditsPerMonth - $creditsConsumed, 2)
|
|
$creditsUsagePercent = if ($creditsPerMonth -gt 0) {
|
|
[math]::Round(($creditsConsumed / $creditsPerMonth) * 100, 2)
|
|
} else {
|
|
0
|
|
}
|
|
|
|
# Determine if credits are being wasted (assigned but not actively using)
|
|
$isWastingCredits = ($creditsConsumed -gt 0) -and ($daysSinceLastActivity -eq $null -or $daysSinceLastActivity -gt 30)
|
|
|
|
[PSCustomObject]@{
|
|
Username = $username
|
|
DisplayName = $_.assignee.name
|
|
Email = $_.assignee.email
|
|
AssignedAt = $assignedDateFormatted
|
|
LastActivityAt = if ($lastActivityDate) { $lastActivityDate.ToString("yyyy-MM-dd HH:mm:ss") } else { "Never" }
|
|
DaysSinceLastActivity = if ($daysSinceLastActivity -ne $null) { $daysSinceLastActivity } else { "N/A" }
|
|
IsActive30Days = $isActive
|
|
IsWastingCredits = $isWastingCredits
|
|
DaysAssignedThisMonth = if ($assignedDate) { $daysAssignedThisMonth } else { $currentDay }
|
|
CreditsAllocated = $creditsPerMonth
|
|
CreditsConsumed = $creditsConsumed
|
|
CreditsRemaining = $creditsRemaining
|
|
CreditsUsagePercent = $creditsUsagePercent
|
|
PendingCancellationDate = if ($_.pending_cancellation_date) { $_.pending_cancellation_date } else { "" }
|
|
Editor = $_.last_activity_editor
|
|
AssigningTeam = if ($_.assigning_team) { $_.assigning_team.name } else { "" }
|
|
}
|
|
} | Sort-Object CreditsConsumed -Descending
|
|
|
|
Write-Host "Total Seats Assigned: $($userSeats.Count)" -ForegroundColor Cyan
|
|
$activeUsers = ($userSeats | Where-Object { $_.IsActive30Days -eq $true }).Count
|
|
$inactiveUsers = ($userSeats | Where-Object { $_.IsActive30Days -eq $false }).Count
|
|
$wastingCredits = ($userSeats | Where-Object { $_.IsWastingCredits -eq $true }).Count
|
|
|
|
Write-Host "Active Users (last 30 days): $activeUsers" -ForegroundColor Green
|
|
Write-Host "Inactive Users: $inactiveUsers" -ForegroundColor Yellow
|
|
Write-Host "Users Wasting Credits: $wastingCredits" -ForegroundColor Red
|
|
Write-Host ""
|
|
|
|
# Show top users by credit consumption
|
|
Write-Host "All Users by Credit Consumption (Month of $(Get-Date -Format 'MMMM yyyy')):" -ForegroundColor Yellow
|
|
$userSeats | Select-Object -First 50 |
|
|
Format-Table Username, DaysAssignedThisMonth, CreditsConsumed, CreditsUsagePercent, LastActivityAt, IsWastingCredits, Editor -AutoSize
|
|
|
|
# Show users wasting credits
|
|
Write-Host ""
|
|
Write-Host "Users WASTING Credits (assigned but inactive >30 days):" -ForegroundColor Red
|
|
$userSeats | Where-Object { $_.IsWastingCredits -eq $true } |
|
|
Select-Object -First 50 |
|
|
Format-Table Username, CreditsConsumed, DaysSinceLastActivity, LastActivityAt, AssignedAt -AutoSize
|
|
|
|
# Credit usage summary
|
|
$totalCreditsAllocated = $userSeats.Count * $creditsPerMonth
|
|
$totalCreditsConsumed = ($userSeats | Measure-Object -Property CreditsConsumed -Sum).Sum
|
|
$totalCreditsWasted = ($userSeats | Where-Object { $_.IsWastingCredits -eq $true } | Measure-Object -Property CreditsConsumed -Sum).Sum
|
|
$creditEfficiency = if ($totalCreditsAllocated -gt 0) {
|
|
[math]::Round(($totalCreditsConsumed / $totalCreditsAllocated) * 100, 2)
|
|
} else { 0 }
|
|
|
|
Write-Host ""
|
|
Write-Host "=== CREDIT USAGE ANALYSIS (Month of $(Get-Date -Format 'MMMM yyyy')) ===" -ForegroundColor Green
|
|
Write-Host "Credits per User per Month: $creditsPerMonth" -ForegroundColor White
|
|
Write-Host "Total Seats: $($userSeats.Count)" -ForegroundColor White
|
|
Write-Host "Total Credits Allocated (Full Month): $totalCreditsAllocated ($($userSeats.Count) users x $creditsPerMonth)" -ForegroundColor White
|
|
Write-Host "Total Credits Consumed (Month-to-Date): $([math]::Round($totalCreditsConsumed, 2))" -ForegroundColor Cyan
|
|
Write-Host "Total Credits on WASTED Seats: $([math]::Round($totalCreditsWasted, 2))" -ForegroundColor Red
|
|
Write-Host "Potential Monthly Savings (remove inactive): $([math]::Round(($wastingCredits * $creditsPerMonth), 2)) credits" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host "Days Elapsed in Month: $currentDay of $daysInMonth" -ForegroundColor White
|
|
Write-Host "Credit Utilization: $creditEfficiency% (of full-month allocation)" -ForegroundColor $(if ($creditEfficiency -lt 50) { "Red" } elseif ($creditEfficiency -lt 75) { "Yellow" } else { "Green" })
|
|
Write-Host ""
|
|
|
|
# Recommendations
|
|
if ($wastingCredits -gt 0) {
|
|
Write-Host "💡 RECOMMENDATIONS:" -ForegroundColor Cyan
|
|
Write-Host " → Remove $wastingCredits inactive user(s) to save ~$([math]::Round(($wastingCredits * $creditsPerMonth), 2)) credits/month" -ForegroundColor Yellow
|
|
Write-Host " → That's approximately `$$([math]::Round(($wastingCredits * 19), 2))/month in wasted costs (at ~`$19/seat)" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Warning "Failed to retrieve user seat information: $_"
|
|
Write-Host "You may need 'manage_billing:copilot' scope to access seat details." -ForegroundColor Yellow
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Error "An error occurred: $_"
|
|
exit 1
|
|
}
|
|
|
|
# Export to Excel if requested
|
|
if (-not [string]::IsNullOrEmpty($ExportToExcel)) {
|
|
Write-Host ""
|
|
Write-Host "Exporting to Excel: $ExportToExcel" -ForegroundColor Cyan
|
|
|
|
try {
|
|
# Remove existing file if it exists
|
|
if (Test-Path $ExportToExcel) {
|
|
Remove-Item $ExportToExcel -Force
|
|
}
|
|
|
|
# Export to multiple worksheets
|
|
$excelParams = @{
|
|
Path = $ExportToExcel
|
|
AutoSize = $true
|
|
FreezeTopRow = $true
|
|
BoldTopRow = $true
|
|
}
|
|
|
|
$sheetCount = 1
|
|
|
|
# Sheet 1: Overall Summary
|
|
if ($null -ne $overallSummary) {
|
|
$overallSummary | Export-Excel @excelParams -WorksheetName "Overall Summary" -TableName "OverallSummary"
|
|
$sheetCount++
|
|
}
|
|
|
|
# Sheet 2: Daily Summary
|
|
if ($dailySummary.Count -gt 0) {
|
|
$dailySummary | Export-Excel @excelParams -WorksheetName "Daily Summary" -TableName "DailySummary"
|
|
$sheetCount++
|
|
}
|
|
|
|
# Sheet 3: Language Breakdown
|
|
if ($languageSummary.Count -gt 0) {
|
|
$languageSummary | Export-Excel @excelParams -WorksheetName "Language Breakdown" -TableName "LanguageBreakdown"
|
|
$sheetCount++
|
|
}
|
|
|
|
# Sheet 4: Editor Breakdown
|
|
if ($editorSummary.Count -gt 0) {
|
|
$editorSummary | Export-Excel @excelParams -WorksheetName "Editor Breakdown" -TableName "EditorBreakdown"
|
|
$sheetCount++
|
|
}
|
|
|
|
# Sheet 5: Detailed Metrics
|
|
if ($userMetrics.Count -gt 0) {
|
|
$userMetrics | Sort-Object Date -Descending |
|
|
Export-Excel @excelParams -WorksheetName "Detailed Metrics" -TableName "DetailedMetrics"
|
|
$sheetCount++
|
|
}
|
|
|
|
# Sheet 6: User Seats (if included)
|
|
if ($userSeats.Count -gt 0) {
|
|
$userSeats | Export-Excel @excelParams -WorksheetName "User Seats" -TableName "UserSeats"
|
|
$sheetCount++
|
|
}
|
|
|
|
Write-Host "Results exported to: $ExportToExcel" -ForegroundColor Green
|
|
Write-Host "Excel file contains multiple worksheets:" -ForegroundColor Green
|
|
Write-Host " - Overall Summary" -ForegroundColor White
|
|
Write-Host " - Daily Summary" -ForegroundColor White
|
|
Write-Host " - Language Breakdown" -ForegroundColor White
|
|
Write-Host " - Editor Breakdown" -ForegroundColor White
|
|
Write-Host " - Detailed Metrics" -ForegroundColor White
|
|
if ($userSeats.Count -gt 0) {
|
|
Write-Host " - User Seats (per-user credit information)" -ForegroundColor White
|
|
}
|
|
} catch {
|
|
Write-Error "Failed to export to Excel: $_"
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Note: For individual user seat management in browser, visit:" -ForegroundColor Cyan
|
|
Write-Host "https://github.com/organizations/$Organization/settings/copilot/seat_management" -ForegroundColor Cyan
|
|
|
|
Write-Host ""
|
|
Write-Host "Script completed." -ForegroundColor Green
|