Use this to create the App for the Tenantid\clientid and ClientSecret
# Define variables with your values
$tenantId = "xxxx"
$clientId = "xxxxx"
$clientSecret = "xxxxxx"
$outputFile = "C:\Temp\AllGenerativeAIUsage.csv"
# Function to get an access token
function Get-AccessToken {
param (
[string]$TenantId,
[string]$ClientId,
[string]$ClientSecret
)
$tokenUrl = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token"
$body = @{
grant_type = "client_credentials"
client_id = $ClientId
client_secret = $ClientSecret
scope = "https://graph.microsoft.com/.default"
}
try {
$tokenResponse = Invoke-RestMethod -Uri $tokenUrl -Method Post -Body $body
Write-Host "Access Token obtained successfully."
return $tokenResponse.access_token
} catch {
Write-Error "Failed to obtain access token: $_"
exit
}
}
# Get the access token
$accessToken = Get-AccessToken -TenantId $tenantId -ClientId $clientId -ClientSecret $clientSecret
$headers = @{
"Authorization" = "Bearer $accessToken"
"Content-Type" = "application/json"
}
# Get all streams
$streamsUrl = "https://graph.microsoft.com/beta/security/dataDiscovery/cloudAppDiscovery/uploadedStreams"
try {
$streamsResponse = Invoke-RestMethod -Uri $streamsUrl -Headers $headers -Method Get
Write-Host "Streams found: $($streamsResponse.value.Count)"
} catch {
Write-Error "Failed to retrieve streams: $_"
exit
}
# Initialize an array to store results
$results = @()
# Loop through each stream to find Generative AI apps
foreach ($stream in $streamsResponse.value) {
$streamId = $stream.id
$streamName = $stream.displayName
Write-Host "Checking stream: $streamName (ID: $streamId)"
# Get all discovered apps for the stream (last 90 days) with pagination
$appsUrl = "https://graph.microsoft.com/beta/security/dataDiscovery/cloudAppDiscovery/uploadedStreams/$streamId/aggregatedAppsDetails(period=duration'P90D')"
$allApps = @()
$nextLink = $appsUrl
while ($nextLink) {
try {
$response = Invoke-RestMethod -Uri $nextLink -Headers $headers -Method Get
$allApps += $response.value
$nextLink = $response.'@odata.nextLink'
Write-Host "Fetched $($allApps.Count) apps so far for stream ${streamName}..."
} catch {
Write-Warning "Failed to retrieve apps for stream ${streamName}: $_"
$nextLink = $null
}
}
Write-Host "Total apps found in stream ${streamName}: $($allApps.Count)"
# Filter for Generative AI category or ChatGPT/OpenAI by name/domain
foreach ($app in $allApps) {
$appId = $app.id
$appName = $app.displayName
$appCategory = $app.category
$appDomain = $app.domain
if ($appCategory -ieq "generativeAi" -or $appName -match "ChatGPT" -or $appName -match "OpenAI" -or $appDomain -match "openai.com") {
Write-Host "Generative AI app found in stream ${streamName}: $appName (ID: $appId, Category: $appCategory, Domain: $appDomain)"
$usersUrl = "$appsUrl/$appId/users"
try {
$usersResponse = Invoke-RestMethod -Uri $usersUrl -Headers $headers -Method Get
Write-Host "Users found for ${appName}: $($usersResponse.value.Count)"
if ($usersResponse.value.Count -gt 0) {
Write-Host "Usernames: $($usersResponse.value.userIdentifier -join ', ')"
}
foreach ($user in $usersResponse.value) {
$results += [PSCustomObject]@{
Stream = $streamName
AppName = $appName
Username = $user.userIdentifier
ActivityCount = $user.activityCount
}
}
} catch {
Write-Warning "Failed to retrieve users for $appName in stream ${streamName}: $_"
}
}
}
}
# Export results to CSV
if ($results.Count -gt 0) {
$results | Export-Csv -Path $outputFile -NoTypeInformation
Write-Host "Generative AI usage exported to $outputFile with $($results.Count) entries."
} else {
Write-Host "No Generative AI usage data found to export across all streams."
}