I managed to figure out how to access emails just usiing application id and secret without
using any non-standard libraries. You'll need to install the Graph and powershell utilities,
but they're free from Microsoft, so I call them standard. Then import them into my powershell
script thus:
Import-Module Microsoft.Graph.Mail
Import-Module Microsoft.PowerShell.Utility
After that, use these methods to access your o365 email system using the microsoft graph
REST API.
# This AuthenticateWithSecret is a slightly modified version of the method
# described by https://adamtheautomator.com/powershell-graph-api/
function Get-AccessToken
{
param(
[string] $AppId,
[string] $TenantName,
[string] $AppSecret)
$Scope = "https://graph.microsoft.com/.default"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
# Add System.Web for urlencode
Add-Type -AssemblyName System.Web
# Create body
$Body = @{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'client_credentials'
}
# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
# Create string by joining bodylist with '&'
Body = $Body
Uri = $Url
}
# Request the token!
$Request = Invoke-RestMethod @PostSplat
return $Request
}
# This method builds a header object that can be passed
# in with each request to the Graph REST API, for authentication
# purposes
function Get-Header
{
param($theRequest)
$tokenType = $theRequest.token_type
$accessToken = $theRequest.access_token
# Create header
$theHeader = @{
Authorization = "$($tokenType) $($accessToken)"
}
return $theHeader
}
# This method gets an object containing the email folders from
# a mailbox specified by its UserPrincipalName - which is typically
# the email address of the user concerned. By default it will return
# the first 200 folders it finds, but you can specify however many
# that you wish to return using the $numberOfFoldersToGet parameter.
function Get-Folders
{
param(
$Credential,
[string] $UserPrincipalName,
[int]$numberOfFoldersToGet=200)
$Header = Get-Header -theRequest $Credential
$restUrl = "https://graph.microsoft.com/v1.0/users/$UserPrincipalName/mailFolders/?`$top=$numberOfFoldersToGet"
$folderResult = Invoke-RestMethod -Uri $restUrl -Headers $Header -Method Get -ContentType "application/json"
return $folderResult
}
# This is a little helper function to get the specific folder object
# from an array of folder objects. You specify the folder that you
# want in the array based o its displayName using the $folderNameToFind
# parameter.
function Get-FolderFromListOfFolders
{
param($listOfFolders,
$folderNameToFind)
$specificFolder = ""
# Yeah, yeah, I know - we're doing this the brute-force way - just
# looping through all the folders until we find the one we want.
# Unless you have an insane number of folders, this shouldn't take
# *that* long, but this loop could be re-written to use a nicer search
# if it's really that big a problem.
foreach($fdr in $allFolders)
{
$thisFolderName = $fdr.displayName
if($thisFolderName -eq $folderNameToFind)
{
$specificFolder = $fdr
break
}
}
return $specificFolder
}
# This function allows you to retrieve an object describing a specific
# mail folder in an o365 Outlook, which you can specify by name. It allows
# you to access any folder by name - not just the common ones.
function Get-SpecificFolder
{
param(
$Credential,
[string] $UserPrincipalName,
[string] $folderName)
$allTheFolders = Get-Folders -Credential $Credential -UserPrincipalName $UserPrincipalName
$allFolders = $allTheFolders.value
$specificFolder = Get-FolderFromListOfFolders -listOfFolders $allFolders -folderNameToFind $folderName
$folderId = $specificFolder.id
$Header = Get-Header -theRequest $Credential
$theRestQuery = "https://graph.microsoft.com/v1.0/users/$UserPrincipalName/mailFolders/$folderId"
$folderResult = Invoke-RestMethod -Uri $theRestQuery -Headers $Header -Method Get -ContentType "application/json"
return $folderResult
}
# This function returns an object containing all the emails in a given
# Mail folder in Outlook in o365
function GetEmails
{
param(
$Credential,
[string] $UserPrincipalName,
[string] $folderId)
$Header = Get-Header -theRequest $Credential
$restUrl = "https://graph.microsoft.com/v1.0/users/$UserPrincipalName/mailFolders/$folderId/messages"
$emailResult = Invoke-RestMethod -Uri $restUrl -Headers $Header -Method Get -ContentType "application/json"
return $emailResult
}
You can use these methods in this way. First, you need to specify these variables
$ClientID = "My-azure-ad-client-id"
$DirectoryID = "My-directory-id"
$ClientSecret = "My-client-secret"
$MailboxName = "the-email-address-of-the-o365-mailbox-i-want-to-access"
$MailboxFolderName = "the-folder-name-of-the-mailfolder-containing-emails"
Then, you can get a credential object thus:
$Credential = Get-AccessToken -AppId $ClientID -TenantName $DirectoryID -AppSecret $ClientSecret
Then get your email folder object thus
$myfolder = Get-SpecificFolder -Credential $Credential -UserPrincipalName $MailboxName -folderName $MailboxFolderName
Then, get the id of your folder - this allows you to access any folder - even non-standard ones by name.
$folderId = $myfolder.id
Now, get the email objects from the folder
$emails = GetEmails -Credential $Credential -UserPrincipalName $MailboxName -folderId $folderId
Then get the actual array of emails
$theEmails = $emails.value
Now loop through your array of emails and do stuff with it.
foreach($email in $theEmails)
{
Write-Output $email.subject
}