-
Notifications
You must be signed in to change notification settings - Fork 140
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 #606 from nanddeepn/teams-pstn-call-logs
New script sample to Export Microsoft Teams PSTN call logs
- Loading branch information
Showing
5 changed files
with
283 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,222 @@ | ||
--- | ||
plugin: add-to-gallery | ||
--- | ||
|
||
# Export Microsoft Teams PSTN Call Logs | ||
|
||
## Summary | ||
|
||
This script exports the log of PSTN 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 ".\PSTN-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/getPstnCalls(fromDateTime=$fromDateTime,toDateTime=$toDateTime)" | ||
ForEach ($record in $callRecords) { | ||
$reportLine = [PSCustomObject][Ordered]@{ | ||
"id" = $record.id | ||
"callId" = $record.callId | ||
"userId" = $record.userId | ||
"userPrincipalName" = $record.userPrincipalName | ||
"userDisplayName" = $record.userDisplayName | ||
"startDateTime" = $record.startDateTime | ||
"endDateTime" = $record.endDateTime | ||
"duration" = $record.duration | ||
"charge" = $record.charge | ||
"callType" = $record.callType | ||
"currency" = $record.currency | ||
"calleeNumber" = $record.calleeNumber | ||
"usageCountryCode" = $record.usageCountryCode | ||
"tenantCountryCode" = $record.tenantCountryCode | ||
"connectionCharge" = $record.connectionCharge | ||
"callerNumber" = $record.callerNumber | ||
"destinationContext" = $record.destinationContext | ||
"destinationName" = $record.destinationName | ||
"conferenceId" = $record.conferenceId | ||
"licenseCapability" = $record.licenseCapability | ||
"inventoryType" = $record.inventoryType | ||
} | ||
$reportLine | Export-Csv -NoTypeInformation -Path ".\PSTN-Data-$((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 pstncalls --fromDateTime $fromDateTime --toDateTime $toDateTime --output csv | Out-File -FilePath ".\PSTN-Data-$((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-pstn-call-logs" 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.
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-pstn-call-logs", | ||
"source": "pnp", | ||
"title": "Export Microsoft Teams PSTN call logs", | ||
"shortDescription": "Exports the log of PSTN calls for a given duration", | ||
"url": "https://pnp.github.io/script-samples/teams-export-pstn-call-logs/README.html", | ||
"longDescription": [ | ||
"Exports the log of PSTN 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 pstncalls" | ||
], | ||
"categories": [ | ||
"Report" | ||
], | ||
"thumbnails": [ | ||
{ | ||
"type": "image", | ||
"order": 100, | ||
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/teams-export-pstn-call-logs/assets/preview.png", | ||
"alt": "Export Microsoft Teams PSTN call logs" | ||
} | ||
], | ||
"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" | ||
} | ||
] | ||
} | ||
] | ||
|