Skip to content

Instantly share code, notes, and snippets.

@AlexanderHolmeset-zz
Created November 10, 2020 12:57
Show Gist options
  • Save AlexanderHolmeset-zz/6a4abb82f1b04361a222a3b0bc668d98 to your computer and use it in GitHub Desktop.
Save AlexanderHolmeset-zz/6a4abb82f1b04361a222a3b0bc668d98 to your computer and use it in GitHub Desktop.
#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