Connexion Exchange Online en PowerShell — pourquoi pas l'API REST ?
Pourquoi pas l'API REST ?
Toutes les APIs Microsoft ne fonctionnent pas de la même façon.
Microsoft Graph, Azure Resource Manager, Azure DevOps ou Key Vault exposent des endpoints REST classiques :
on obtient un Bearer token via Get-Faitza_Modul_Headers, on appelle Invoke-RestMethod, c'est fini.
Exchange Online est une exception. Certes, Microsoft Graph expose quelques endpoints pour les boîtes mail
(/users/{id}/messages, /users/{id}/mailFolders…), mais ils ne couvrent qu'une fraction
des opérations d'administration Exchange. Des fonctionnalités essentielles comme :
- Créer ou convertir une boîte partagée (
New-Mailbox,Set-Mailbox -Type Shared) - Gérer les délégations (
Add-MailboxPermission,Add-RecipientPermission) - Administrer les règles de transport, les connecteurs, les politiques de rétention
- Lister l'ensemble des boîtes avec leurs propriétés Exchange natives
…ne sont disponibles que via les cmdlets du module ExchangeOnlineManagement. Il n'existe pas d'endpoint REST équivalent pour ces opérations. Une connexion au module est donc toujours obligatoire pour administrer Exchange Online en PowerShell.
Microsoft Graph convient pour lire des emails, gérer des calendriers ou des contacts depuis une application. Le module ExchangeOnlineManagement est indispensable pour toute administration Exchange : boîtes partagées, délégations, quotas, audit logs Exchange, règles de flux de messagerie.
Le module ExchangeOnlineManagement
Le module officiel s'installe depuis la PowerShell Gallery :
Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser -Force
La connexion standard se fait via Connect-ExchangeOnline. En environnement interactif,
une fenêtre de login s'ouvre. En environnement automatisé, on passe un token Bearer
obtenu depuis Azure CLI via le paramètre -AccessToken — c'est ce que fait
Connect-Faitza_Modul_ExchangeOnline.
La ressource OAuth2 attendue pour Exchange Online est https://outlook.office365.com/.
Elle est différente de la ressource Graph : un token Graph ne fonctionnera pas ici.
Connect-Faitza_Modul_ExchangeOnline
La fonction est définie dans Faitza_Function/Faitza_Modul/Faitza_Modul.ps1,
aux côtés de Get-Faitza_Modul_Headers.
Elle encapsule le flux complet : import silencieux du module, détection d'une session existante
(idempotent), récupération du token via Azure CLI, connexion.
function Connect-Faitza_Modul_ExchangeOnline {
[CmdletBinding()]
param(
[string]$organization = "faitza.onmicrosoft.com",
[switch]$deco
)
Write-Host "$($PSStyle.Background.Red)>>> Connect-Faitza_Modul_ExchangeOnline <<<$($PSStyle.Reset)"
try {
if ($deco) {
Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
Write-Host "Déconnexion Exchange effectuée."
return
}
# Import silencieux du module pour éviter les warnings
$oldErrPref = $ErrorActionPreference
$ErrorActionPreference = 'SilentlyContinue'
try { Import-Module ExchangeOnlineManagement -ErrorAction SilentlyContinue } catch {}
$ErrorActionPreference = $oldErrPref
# Vérification de session existante — idempotent
if (Get-ConnectionInformation -ErrorAction SilentlyContinue) {
Write-Host "Déjà connecté à Exchange Online."
return "Connect : OK"
}
# Token obtenu via Azure CLI (ressource outlook.office365.com)
$Token = az account get-access-token `
--resource "https://outlook.office365.com/" `
--query accessToken -o tsv
if ([string]::IsNullOrWhiteSpace($Token)) {
throw "Le jeton retourné par Azure CLI est vide."
}
Connect-ExchangeOnline `
-Organization $organization `
-AccessToken $Token `
-ShowBanner:$false `
-ErrorAction Stop
$domain = Get-AcceptedDomain | Where-Object { $_.Default -eq $true }
Write-Host "$($PSStyle.Foreground.BrightGreen)Connexion Exchange réussie : $($domain.Name)$($PSStyle.Reset)"
return "Connect : $($domain.Name)"
} catch {
throw "Erreur connexion ExchangeOnline : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< Connect-Faitza_Modul_ExchangeOnline >>>$($PSStyle.Reset)"
}
}
Points clés :
-
Import silencieux —
ExchangeOnlineManagementaffiche des warnings à l'import. La fonction coupe temporairement$ErrorActionPreferencepour les supprimer. -
Idempotence —
Get-ConnectionInformationdétecte si une session Exchange est déjà active. Si c'est le cas, la fonction sort immédiatement sans reconnecter. -
Token via Azure CLI —
az account get-access-tokenretourne un token pour la ressourceoutlook.office365.com. Ce token est passé directement àConnect-ExchangeOnline. -
Switch
-deco— Déconnecte proprement la session Exchange en fin de script.
Utilisation
En début de script Exchange, on appelle la fonction une fois. Toutes les cmdlets Exchange sont ensuite disponibles dans la session jusqu'à la déconnexion.
# Connexion
Connect-Faitza_Modul_ExchangeOnline
# Cmdlets Exchange disponibles dès maintenant
$mailboxes = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails SharedMailbox
$mailboxes | Select-Object DisplayName, PrimarySmtpAddress
# Déconnexion en fin de script
Connect-Faitza_Modul_ExchangeOnline -deco
Voir l'article Exchange Online — boîtes partagées, délégations et automatisation
pour des exemples complets avec Get-Faitza_Exchange_SharedMailbox,
Add-Faitza_Exchange_MailboxDelegation, etc.
Liens Microsoft
- Connect-ExchangeOnline — learn.microsoft.com
- ExchangeOnlineManagement module — learn.microsoft.com
- Azure CLI : get-access-token — learn.microsoft.com
Pièges
La ressource pour Exchange Online est https://outlook.office365.com/,
pas https://graph.microsoft.com. Un token obtenu avec
Get-Faitza_Modul_Headers -resource "graph" sera rejeté par Connect-ExchangeOnline.
Le compte ou la Managed Identity utilisé doit avoir le rôle Exchange approprié dans Microsoft 365 (ex. Exchange Administrator ou un rôle RBAC Exchange personnalisé). Un token valide ne suffit pas si le compte n'a pas les permissions Exchange.
Toujours appeler Connect-Faitza_Modul_ExchangeOnline -deco en fin de script
pour libérer la session Exchange côté serveur. Les sessions abandonnées consomment des ressources
et peuvent atteindre les limites de connexion simultanées.
// Commentaires
Aucun commentaire pour l'instant.