faitza.com
faitza.com
> blog_tech

Exchange Online : connexion, boîtes partagées et délégations en PowerShell

Calcul... powershell exchange-online microsoft-365 automation
Exchange Online + PowerShell

Introduction

Faitza_Exchange.ps1 regroupe les fonctions PowerShell pour administrer Exchange Online : audit des permissions, gestion des boîtes partagées, conversions et délégations. La connexion est gérée par Connect-Faitza_Modul_ExchangeOnline via le module ExchangeOnlineManagement et Azure CLI — les cmdlets Exchange ne sont pas disponibles via REST Graph, d'où l'utilisation du module PowerShell dédié.

Prérequis
  • Module ExchangeOnlineManagement installé : Install-Module ExchangeOnlineManagement
  • Azure CLI connecté avec un compte ayant les droits Exchange Admin
  • Appeler Connect-Faitza_Modul_ExchangeOnline avant toute autre fonction

Connect — Se connecter à Exchange Online

Établit la connexion à Exchange Online via un token obtenu depuis Azure CLI (az account get-access-token). Détecte automatiquement si une session est déjà active pour éviter les doubles connexions. Le switch -deco déconnecte proprement la session en cours.

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
        }

        $oldErrPref = $ErrorActionPreference
        $ErrorActionPreference = 'SilentlyContinue'
        try { Import-Module ExchangeOnlineManagement -ErrorAction SilentlyContinue } catch {}
        $ErrorActionPreference = $oldErrPref

        if (Get-ConnectionInformation -ErrorAction SilentlyContinue) {
            Write-Host "Déjà connecté à Exchange Online."
            return "Connect : OK"
        }

        $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)"
    }
}
# Connexion (tenant par défaut)
Connect-Faitza_Modul_ExchangeOnline

# Connexion sur un autre tenant
Connect-Faitza_Modul_ExchangeOnline -organization "contoso.onmicrosoft.com"

# Déconnexion propre
Connect-Faitza_Modul_ExchangeOnline -deco

SharedMailbox — Lister et auditer

Sans paramètre, retourne toutes les boîtes partagées du tenant (DisplayName, UPN, adresse SMTP). Avec un nom ou une adresse SMTP, retourne le détail des permissions : FullAccess, SendAs et SendOnBehalf, regroupés par utilisateur délégué.

function Get-Faitza_Exchange_SharedMailbox {
    [CmdletBinding()]
    param (
        [string]$mail
    )

    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Exchange_SharedMailbox <<<$($PSStyle.Reset)"

        if ([string]::IsNullOrWhiteSpace($mail)) {
            Write-Host "$($PSStyle.Foreground.BrightCyan)Récupération des Shared Mailboxes via Exchange Online...$($PSStyle.Reset)"
            $SharedMailboxes = Get-EXOMailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited -Properties UserPrincipalName, DisplayName, PrimarySmtpAddress -ErrorAction Stop

            $Results = foreach ($mbx in $SharedMailboxes) {
                [pscustomobject]@{
                    DisplayName        = $mbx.DisplayName
                    UserPrincipalName  = $mbx.UserPrincipalName
                    PrimarySmtpAddress = $mbx.PrimarySmtpAddress
                }
            }

            Write-Host "$($PSStyle.Foreground.BrightGreen)Nombre de Shared Mailboxes trouvées : $(@($Results).Count)$($PSStyle.Reset)"
            return $Results
        }

        $liste_permission = @{
            "FullAccess"   = "Lecture et gestion"
            "SendAs"       = "Envoyer en tant que"
            "SendOnBehalf" = "Envoyer de la part de"
        }

        if ($mail -notlike "*@faitza.com") {
            $mail_filter = "RecipientTypeDetails -eq 'SharedMailbox' -and Displayname -eq '$mail'"
            $mail_find = Get-Mailbox -ResultSize Unlimited -Filter $mail_filter -ErrorAction Stop
        } else {
            $mail_find = Get-Mailbox -Identity $mail -ErrorAction Stop
            if ($mail_find.RecipientTypeDetails -ne "SharedMailbox") { throw "$mail n'est pas une SharedMailbox" }
        }

        if (-not $mail_find.PrimarySmtpAddress) { throw "Aucune adresse SMTP trouvée pour $mail" }

        $mail_id = $mail_find.PrimarySmtpAddress
        $mail_name = $mail_find.DisplayName

        $liste_full = Get-MailboxPermission -Identity $mail_id -ErrorAction Stop |
            Where-Object { $_.AccessRights -contains "FullAccess" -and -not $_.IsInherited -and $_.User -ne "NT AUTHORITY\SELF" -and $_.User -notlike "S-*" } |
            ForEach-Object {
                [pscustomobject]@{
                    Nom        = $mail_name
                    Mail       = $mail_id
                    Permission = "FullAccess"
                    User       = $_.User.ToString()
                }
            }

        $liste_send = Get-RecipientPermission -Identity $mail_id -ErrorAction Stop |
            Where-Object { -not $_.IsInherited -and $_.Trustee -ne "NT AUTHORITY\SELF" -and $_.Trustee -notlike "S-*" } |
            ForEach-Object {
                foreach ($mail_accessright in ($_.AccessRights | ForEach-Object { $_.ToString() })) {
                    [pscustomobject]@{
                        Nom        = $mail_name
                        Mail       = $mail_id
                        Permission = $mail_accessright
                        User       = $_.Trustee.ToString()
                    }
                }
            }

        $liste_sob = $mail_find.GrantSendOnBehalfTo | ForEach-Object {
            [pscustomobject]@{
                Nom        = $mail_name
                Mail       = $mail_id
                Permission = "SendOnBehalf"
                User       = $_.ToString()
            }
        }

        $result = @($liste_full) + @($liste_send) + @($liste_sob) |
            Group-Object -Property Mail, User |
            ForEach-Object {
                $groupe = $_.Group
                [pscustomobject]@{
                    Nom   = $groupe[0].Nom
                    Mail  = $groupe[0].Mail
                    User  = $groupe[0].User
                    Droit = ($liste_permission[$groupe.Permission] | Sort-Object -Unique) -join " ; "
                }
            }

        Write-Host "Ok : $($mail_find.DisplayName) : $($mail_find.PrimarySmtpAddress)"
        return $result
    } catch {
        throw "Erreur Get-Faitza_Exchange_SharedMailbox : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Exchange_SharedMailbox >>>$($PSStyle.Reset)"
    }
}
# Lister toutes les boîtes partagées
$sharedMailboxes = Get-Faitza_Exchange_SharedMailbox
$sharedMailboxes | Format-Table DisplayName, PrimarySmtpAddress -AutoSize

# Permissions d'une boîte partagée par adresse
Get-Faitza_Exchange_SharedMailbox -mail "[email protected]" | Format-Table Nom, User, Droit -AutoSize

# Permissions par nom d'affichage
Get-Faitza_Exchange_SharedMailbox -mail "Support IT" | Format-Table -AutoSize

Convert — Convertir en boîte partagée

Convertit une boîte aux lettres utilisateur en boîte partagée via Set-Mailbox -Type Shared. Utile lors du départ d'un employé pour conserver l'accès à son historique mail sans licence active.

function Convert-Faitza_Exchange_user_shearmb {
    [CmdletBinding()]
    param ([string]$UserEmail)

    try {
        Write-Host "$($PSStyle.Background.Red)>>> Convert-Faitza_Exchange_user_shearmb <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($UserEmail)) { throw "Il manque l'email de l'utilisateur -UserEmail" }
        Write-Host "Email : $UserEmail"
        Write-Host "Conversion de $UserEmail en Shared Mailbox"
        Set-Mailbox -Identity $UserEmail -Type Shared -ErrorAction Stop
        return $true
    } catch {
        throw "Erreur Convert-Faitza_Exchange_user_shearmb : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Convert-Faitza_Exchange_user_shearmb >>>$($PSStyle.Reset)"
    }
}
# Convertir la boîte d'un utilisateur parti
Convert-Faitza_Exchange_user_shearmb -UserEmail "[email protected]"

CloudSharedMailbox — Créer une boîte partagée cloud

Crée une boîte partagée cloud-only (sans licence), configure optionnellement un message d'absence automatique et applique les délégations FullAccess en une seule commande. Inclut une attente de 20 secondes pour la réplication Exchange Online.

function New-Faitza_Exchange_CloudSharedMailbox {
    [CmdletBinding()]
    param (
        [string]$Email,
        [string]$OooMessage,
        [string[]]$Delegates
    )

    try {
        Write-Host "$($PSStyle.Background.Red)>>> New-Faitza_Exchange_CloudSharedMailbox <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($Email)) { throw "Il manque l'adresse email (-Email)" }

        $Alias = $Email.Split("@")[0]
        $NomAffiche = "Archive $Alias"

        Write-Host "Création de la Shared Mailbox Cloud-Only : $Email"
        New-Mailbox -Shared -Name "${Alias}_Archive" -DisplayName $NomAffiche -PrimarySmtpAddress $Email -ErrorAction Stop

        Write-Host "Attente de 20s pour la réplication Exchange Online"
        Start-Sleep -Seconds 20

        if ($OooMessage) {
            Write-Host "Configuration du message d'absence"
            $OooHtml = $OooMessage -replace "`r`n", "<br>" -replace "`n", "<br>"
            Set-MailboxAutoReplyConfiguration -Identity $Email -AutoReplyState Enabled -InternalMessage $OooHtml -ExternalMessage $OooHtml -ErrorAction Stop
        }

        if ($Delegates -and $Delegates.Count -gt 0) {
            Write-Host "Application des délégations"
            foreach ($Delegate in $Delegates) {
                $DelClean = $Delegate.Trim()
                if ($DelClean) { Add-MailboxPermission -Identity $Email -User $DelClean -AccessRights FullAccess -InheritanceType All -AutoMapping $true -ErrorAction Stop }
            }
        }

        Write-Host "$($PSStyle.Foreground.BrightGreen)Boîte partagée Cloud configurée avec succès.$($PSStyle.Reset)"
        return $true
    } catch {
        throw "Erreur New-Faitza_Exchange_CloudSharedMailbox : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< New-Faitza_Exchange_CloudSharedMailbox >>>$($PSStyle.Reset)"
    }
}
# Boîte partagée simple
New-Faitza_Exchange_CloudSharedMailbox -Email "[email protected]"

# Avec message d'absence et délégués
New-Faitza_Exchange_CloudSharedMailbox `
    -Email       "[email protected]" `
    -OooMessage  "Jean Dupont a quitté l'entreprise. Contacter [email protected]." `
    -Delegates   @("[email protected]", "[email protected]")

MailboxDelegation — Ajouter une délégation

Accorde simultanément les droits FullAccess (avec AutoMapping) et SendAs à un ou plusieurs utilisateurs sur une boîte partagée existante. Gère plusieurs délégataires en une seule commande et retourne les erreurs individuelles sans interrompre les autres attributions.

function Add-Faitza_Exchange_MailboxDelegation {
    [CmdletBinding()]
    param (
        $SharedMailboxEmail,
        [string[]]$Delegates
    )

    try {
        Write-Host "$($PSStyle.Background.Red)>>> Add-Faitza_Exchange_MailboxDelegation <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($SharedMailboxEmail)) { throw "Aucune boîte partagée cible définie (-SharedMailboxEmail)" }
        if (-not $Delegates -or $Delegates.Count -eq 0) { throw "Aucun délégataire à configurer (-Delegates)" }

        $erreur = @()
        foreach ($Delegate in $Delegates) {
            if ([string]::IsNullOrWhiteSpace($Delegate)) { continue }

            $CleanDelegate = $Delegate.Trim()
            Write-Host "Configuration des droits pour : $CleanDelegate"

            try {
                Add-MailboxPermission -Identity $SharedMailboxEmail -User $CleanDelegate -AccessRights FullAccess -InheritanceType All -AutoMapping $true -ErrorAction Stop
                Add-RecipientPermission -Identity $SharedMailboxEmail -Trustee $CleanDelegate -AccessRights SendAs -Confirm:$false -ErrorAction Stop
                Write-Host "Délégations FullAccess + SendAs accordées avec succès à $CleanDelegate"
            } catch {
                $erreur += "Erreur lors de l'attribution des droits pour $CleanDelegate : $($_.Exception.Message)"
            }
        }

        if ($erreur) { throw ($erreur -join "`n") }

        return $true
    } catch {
        throw "Erreur Add-Faitza_Exchange_MailboxDelegation : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Add-Faitza_Exchange_MailboxDelegation >>>$($PSStyle.Reset)"
    }
}
# Ajouter un délégataire
Add-Faitza_Exchange_MailboxDelegation `
    -SharedMailboxEmail "[email protected]" `
    -Delegates          @("[email protected]")

# Plusieurs délégataires en une commande
Add-Faitza_Exchange_MailboxDelegation `
    -SharedMailboxEmail "[email protected]" `
    -Delegates          @("[email protected]", "[email protected]")

// Commentaires

Aucun commentaire pour l'instant.