-
Notifications
You must be signed in to change notification settings - Fork 143
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #608 from nanddeepn/teams-direct-routing-calls
New script sample to Export Microsoft Teams DirectRoutingCalls
- Loading branch information
Showing
5 changed files
with
282 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
--- | ||
plugin: add-to-gallery | ||
--- | ||
|
||
# Export Microsoft Teams Direct Routing Calls | ||
|
||
## Summary | ||
|
||
This script exports the log of direct routing calls for a given duration. | ||
|
||
![Example Screenshot](assets/example.png) | ||
|
||
## Permissions | ||
|
||
The PowerShell version of the script requires Microsoft Entra ID App Registration with the Application Permission as follows: | ||
1. CallRecord-PstnCalls.Read.All | ||
2. CallRecords.Read.All | ||
|
||
![Permission](assets/API_Permissions.png) | ||
|
||
> Note: You can skip this step, if you are planning to use CLI for Microsoft 365. | ||
## Implementation | ||
|
||
- Open Windows PowerShell ISE | ||
- Create a new file | ||
- Copy the code below | ||
- Save the file and run it | ||
|
||
# [PowerShell](#tab/ps) | ||
|
||
```powershell | ||
[CmdletBinding()] | ||
param ( | ||
[parameter(Mandatory)][string] $TenantID, | ||
[parameter(Mandatory)][string] $ClientID, | ||
[parameter(Mandatory)][string] $ClientSecret, | ||
[parameter(Mandatory)][DateTime] $StartDate, | ||
[parameter(Mandatory = $false)][DateTime] $EndDate = (Get-Date) | ||
) | ||
function Get-AccessToken { | ||
# Construct URI | ||
$uri = "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" | ||
# Construct Body | ||
$body = @{ | ||
client_id = $ClientID | ||
client_secret = $ClientSecret | ||
scope = 'https://graph.microsoft.com/.default' | ||
grant_type = 'client_credentials' | ||
} | ||
# Fix for issue: The underlying connection was closed | ||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | ||
# Get OAuth 2.0 Token | ||
$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType 'application/x-www-form-urlencoded' -Body $body -UseBasicParsing | ||
# Access Token | ||
return ($tokenRequest.Content | ConvertFrom-Json).access_token | ||
} | ||
function Get-GraphQueryOutput { | ||
param( | ||
[parameter(Mandatory = $true)][String] $Uri | ||
) | ||
$retryCount = 0 | ||
$maxRetries = 3 | ||
$pauseDuration = 2 | ||
$token = Get-AccessToken | ||
$allRecords = @() | ||
while ($Uri) { | ||
try { | ||
Write-Host "Invoking Graph query: $($Uri)" | ||
$query = Invoke-RestMethod -Method Get -Uri $Uri -ContentType 'application/json;odata.metadata=none' -Headers @{Authorization = "Bearer $token" } | ||
$recordToAdd = ($query | Select-Object Value).Value | ||
if (-not $recordToAdd) { | ||
$recordToAdd = $query | ||
} | ||
$allRecords += $recordToAdd | ||
if ($query.'@odata.nextLink') { | ||
# set the url to get the next page of records | ||
$Uri = $query.'@odata.nextLink' | ||
} | ||
else { | ||
$Uri = $null | ||
} | ||
} | ||
catch { | ||
Write-Host "StatusCode: " $_.Exception.Response.StatusCode.value__ | ||
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription | ||
if ($_.Exception.Response.StatusCode.value__ -eq 401) { | ||
$token = Get-AccessToken | ||
} | ||
if ($_.ErrorDetails.Message) { | ||
Write-Host "Inner Error: $_.ErrorDetails.Message" -ForegroundColor Red | ||
} | ||
if ($_.Exception.Response.StatusCode.value__ -eq 404) { | ||
# If the error is "Not Found", let us not retry | ||
$retryCount = $maxRetries + 1 | ||
} | ||
if ($retryCount -ge $maxRetries) { | ||
# Not going to retry again | ||
$Uri = $null | ||
Write-Host "Not going to retry..." -ForegroundColor Red | ||
} | ||
else { | ||
$retryCount += 1 | ||
$pauseDuration = $pauseDuration * 5 | ||
Write-Host "Retry attempt $retryCount after a $pauseDuration second pause..." -ForegroundColor Yellow | ||
Start-Sleep -Seconds $pauseDuration | ||
} | ||
} | ||
} | ||
return $allRecords | ||
} | ||
Start-Transcript -Path ".\DirectRoutingCalls-Logs-$((Get-Date).toString("dd-MM-yyyy")).log" | ||
$timeSpan = New-TimeSpan -Start (Get-Date -Date $StartDate) -End (Get-Date -Date $EndDate) | ||
if ($timeSpan.Days -gt 90) { | ||
Write-Host "The maximum number of days between StartDate and EndDate cannot exceed 90" -ForegroundColor Red | ||
Write-Host "Please try again with a smaller time span." -ForegroundColor Red | ||
Exit | ||
} | ||
$fromDateTime = Get-Date -Date $StartDate -Format "yyyy-MM-dd" | ||
$toDateTime = Get-Date -Date $EndDate -Format "yyyy-MM-dd" | ||
$callRecords = Get-GraphQueryOutput -Uri "https://graph.microsoft.com/v1.0/communications/callRecords/getDirectRoutingCalls(fromDateTime=$fromDateTime,toDateTime=$toDateTime)" | ||
ForEach ($record in $callRecords) { | ||
$reportLine = [PSCustomObject][Ordered]@{ | ||
"id" = $record.id | ||
"correlationId" = $record.correlationId | ||
"userId" = $record.userId | ||
"userPrincipalName" = $record.userPrincipalName | ||
"userDisplayName" = $record.userDisplayName | ||
"startDateTime" = $record.startDateTime | ||
"inviteDateTime" = $record.inviteDateTime | ||
"failureDateTime" = $record.failureDateTime | ||
"endDateTime" = $record.endDateTime | ||
"duration" = $record.duration | ||
"callType" = $record.callType | ||
"successfulCall" = $record.successfulCall | ||
"callerNumber" = $record.callerNumber | ||
"calleeNumber" = $record.calleeNumber | ||
"mediaPathLocation" = $record.mediaPathLocation | ||
"signalingLocation" = $record.signalingLocation | ||
"finalSipCode" = $record.finalSipCode | ||
"callEndSubReason" = $record.callEndSubReason | ||
"finalSipCodePhrase" = $record.finalSipCodePhrase | ||
"trunkFullyQualifiedDomainName" = $record.trunkFullyQualifiedDomainName | ||
"mediaBypassEnabled" = $record.mediaBypassEnabled | ||
} | ||
$reportLine | Export-Csv -NoTypeInformation -Path ".\DirectRoutingCalls-$((Get-Date).toString("dd-MM-yyyy")).csv" -Encoding UTF8 -Append | ||
} | ||
Write-Host "Finished!" -ForegroundColor Green | ||
Stop-Transcript | ||
``` | ||
[!INCLUDE [More about PowerShell](../../docfx/includes/MORE-PS.md)] | ||
|
||
# [CLI for Microsoft 365](#tab/cli-m365-ps) | ||
|
||
```powershell | ||
[CmdletBinding()] | ||
param ( | ||
[parameter(Mandatory)][DateTime] $StartDate, | ||
[parameter(Mandatory = $false)][DateTime] $EndDate = (Get-Date) | ||
) | ||
begin { | ||
Write-Host "Connecting..." -ForegroundColor Yellow | ||
$m365Status = m365 status | ||
if ($m365Status -match "Logged Out") { | ||
m365 login | ||
} | ||
} | ||
process { | ||
$fromDateTime = Get-Date -Date $StartDate -Format "yyyy-MM-dd" | ||
$toDateTime = Get-Date -Date $EndDate -Format "yyyy-MM-dd" | ||
m365 teams report directroutingcalls --fromDateTime $fromDateTime --toDateTime $toDateTime --output csv | Out-File -FilePath ".\DirectRoutingCalls-$((Get-Date).toString("dd-MM-yyyy")).csv" | ||
} | ||
end { | ||
Write-Host "Finished!" -ForegroundColor Green | ||
} | ||
``` | ||
|
||
[!INCLUDE [More about CLI for Microsoft 365](../../docfx/includes/MORE-CLIM365.md)] | ||
|
||
*** | ||
|
||
## Contributors | ||
|
||
| Author(s) | | ||
|-----------| | ||
| [Nanddeep Nachan](https://github.com/nanddeepn) | | ||
| [Smita Nachan](https://github.com/SmitaNachan) | | ||
|
||
## Credits | ||
|
||
The retry invoke REST method requests in PowerShell, when an error occurs is inspired from [this blog](https://blogs.aaddevsup.xyz/2021/01/retry-invoke-restmethod-requests-in-powershell-when-an-error-occurs/). | ||
|
||
[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)] | ||
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/teams-export-direct-routing-calls" aria-hidden="true" /> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions
61
scripts/teams-export-direct-routing-calls/assets/sample.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
[ | ||
{ | ||
"name": "teams-export-direct-routing-calls", | ||
"source": "pnp", | ||
"title": "Export Microsoft Teams Direct Routing Calls", | ||
"shortDescription": "Exports the log of direct routing calls for a given duration", | ||
"url": "https://pnp.github.io/script-samples/teams-export-direct-routing-calls/README.html", | ||
"longDescription": [ | ||
"Exports the log of direct routing calls for a given duration." | ||
], | ||
"creationDateTime": "2023-10-24", | ||
"updateDateTime": "2023-10-24", | ||
"products": [ | ||
"Teams" | ||
], | ||
"metadata": [ | ||
{ | ||
"key": "cli-for-microsoft365", | ||
"value": "7.0.0" | ||
} | ||
], | ||
"tags": [ | ||
"Invoke-WebRequest", | ||
"Invoke-RestMethod", | ||
"m365 login", | ||
"m365 teams report directroutingcalls" | ||
], | ||
"categories": [ | ||
"Report" | ||
], | ||
"thumbnails": [ | ||
{ | ||
"type": "image", | ||
"order": 100, | ||
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/teams-export-direct-routing-calls/assets/preview.png", | ||
"alt": "Export Microsoft Teams Direct Routing Calls" | ||
} | ||
], | ||
"authors": [ | ||
{ | ||
"gitHubAccount": "nanddeepn", | ||
"pictureUrl": "https://github.com/nanddeepn.png", | ||
"name": "Nanddeep Nachan" | ||
}, | ||
{ | ||
"gitHubAccount": "SmitaNachan", | ||
"company": "", | ||
"pictureUrl": "https://github.com/SmitaNachan.png", | ||
"name": "Smita Nachan" | ||
} | ||
], | ||
"references": [ | ||
{ | ||
"name": "Want to learn more about CLI for Microsoft 365 and the commands", | ||
"description": "Check out the CLI for Microsoft 365 site to get started and for the reference to the commands.", | ||
"url": "https://aka.ms/cli-m365" | ||
} | ||
] | ||
} | ||
] | ||
|