#Specify users you need to extract contactlist from. | |
$users = "alexander@contoso.com" | |
#Specify contactlist folder you need to export. Have added wildcard in the request, so if you are exporting all folders thats starts with Skype, enter "Skype" as foldername. | |
#Enter "root" as foldername if you want all contacts that are not in a folder. | |
$folder = "skype" | |
function Get-MSGraphAppToken{ | |
<# .SYNOPSIS | |
Get an app based authentication token required for interacting with Microsoft Graph API | |
.PARAMETER TenantID | |
A tenant ID should be provided. | |
.PARAMETER ClientID | |
Application ID for an Azure AD application. Uses by default the Microsoft Intune PowerShell application ID. | |
.PARAMETER ClientSecret | |
Web application client secret. | |
.EXAMPLE | |
# Manually specify username and password to acquire an authentication token: | |
Get-MSGraphAppToken -TenantID $TenantID -ClientID $ClientID -ClientSecert = $ClientSecret | |
.NOTES | |
Author: Jan Ketil Skanke | |
Contact: @JankeSkanke | |
Created: 2020-15-03 | |
Updated: 2020-15-03 | |
Version history: | |
1.0.0 - (2020-03-15) Function created | |
#> | |
[CmdletBinding()] | |
param ( | |
[parameter(Mandatory = $true, HelpMessage = "Your Azure AD Directory ID should be provided")] | |
[ValidateNotNullOrEmpty()] | |
[string]$TenantID, | |
[parameter(Mandatory = $true, HelpMessage = "Application ID for an Azure AD application")] | |
[ValidateNotNullOrEmpty()] | |
[string]$ClientID, | |
[parameter(Mandatory = $true, HelpMessage = "Azure AD Application Client Secret.")] | |
[ValidateNotNullOrEmpty()] | |
[string]$ClientSecret | |
) | |
Process { | |
$ErrorActionPreference = "Stop" | |
# Construct URI | |
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" | |
# Construct Body | |
$body = @{ | |
client_id = $clientId | |
scope = "https://graph.microsoft.com/.default" | |
client_secret = $clientSecret | |
grant_type = "client_credentials" | |
} | |
try { | |
$MyTokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing | |
$MyToken =($MyTokenRequest.Content | ConvertFrom-Json).access_token | |
If(!$MyToken){ | |
Write-Warning "Failed to get Graph API access token!" | |
Exit 1 | |
} | |
$MyHeader = @{"Authorization" = "Bearer $MyToken" } | |
} | |
catch [System.Exception] { | |
Write-Warning "Failed to get Access Token, Error message: $($_.Exception.Message)"; break | |
} | |
return $MyHeader | |
} | |
} | |
$tenantId = 'xxxxxxxx' | |
$ClientID = 'xxxxxxxx' | |
$ClientSecret = "xxxxxxxx" | |
$global:Header = Get-MSGraphAppToken -TenantID $tenantId -ClientID $ClientID -ClientSecret $ClientSecret | |
function RefreshToken{ | |
Process{ | |
if(!$global:stopwatch){$global:stopwatch = [system.diagnostics.stopwatch]::StartNew()} | |
if(($global:stopwatch.Elapsed).Minutes -eq 45){ | |
$global:stopwatch = [system.diagnostics.stopwatch]::StartNew() | |
$global:Header = Get-MSGraphAppToken -TenantID $tenantId -ClientID $ClientID -ClientSecret $ClientSecret | |
} | |
} | |
} | |
function Get-GraphRequest($uri){ | |
Process { | |
$ErrorActionPreference = "Stop" | |
try { | |
#Graph API request that loops through every '@odata.nextLink'. | |
$content = while (-not [string]::IsNullOrEmpty($Uri)) { | |
# API Call | |
Write-Host "`r`nQuerying $Uri..." -ForegroundColor Yellow | |
try{ | |
RefreshToken | |
$apiCall = Invoke-WebRequest -Method "GET" -Uri $Uri -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing | |
} | |
catch{ | |
Start-Sleep -Seconds 30 | |
$apiCall = Invoke-WebRequest -Method "GET" -Uri $Uri -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing | |
} | |
$nextLink = $null | |
$Uri = $null | |
if ($apiCall.Content) { | |
# Check if any data is left | |
$nextLink = $apiCall.Content | ConvertFrom-Json | Select-Object '@odata.nextLink' | |
$Uri = $nextLink.'@odata.nextLink' | |
$apiCall.Content | ConvertFrom-Json | |
} | |
} | |
} | |
catch [System.Exception] { | |
Write-Warning "Failed to complete request, Error message: $($_.Exception.Message)"; break | |
} | |
return $content.value | |
} | |
} | |
foreach($user in $users){ | |
if($folder -eq 'root'){ | |
$usercontactfolders = Invoke-RestMethod -Method GET -Headers $global:Header "https://graph.microsoft.com/v1.0/users/$($user)/contactfolders/contacts" | |
foreach($usercontactfolder in $usercontactfolders){ | |
$contacts = Get-GraphRequest -uri "https://graph.microsoft.com/v1.0/users/$($user)/contactfolders/$($usercontactfolder.id)/contacts" | |
$customcontacts = @() | |
foreach($contact in $contacts){ | |
$myObject = [PSCustomObject]@{ | |
Name = $contact.displayName | |
email = ($contact.emailaddresses).name | |
} | |
$customcontacts += $myObject | |
} | |
$customcontacts | Export-Csv "c:\temp\$($user)-root.csv" -NoTypeInformation | |
} | |
} | |
Else{ | |
$usercontactfolders = Get-GraphRequest -uri "https://graph.microsoft.com/v1.0/users/$($user)/contactfolders" | Where-Object{$_.displayname -like "$($folder)*"} | |
foreach($usercontactfolder in $usercontactfolders){ | |
$contacts = Get-GraphRequest -uri "https://graph.microsoft.com/v1.0/users/$($user)/contactfolders/$($usercontactfolder.id)/contacts" | |
$customcontacts = @() | |
foreach($contact in $contacts){ | |
$myObject = [PSCustomObject]@{ | |
Name = $contact.displayName | |
email = ($contact.emailaddresses).name | |
} | |
$customcontacts += $myObject | |
} | |
$customcontacts | Export-Csv "c:\temp\$($user)-$($usercontactfolder.displayname).csv" -NoTypeInformation | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment