faitza.com
faitza.com
> blog_tech

Automatiser l'eDiscovery Microsoft 365 avec PowerShell

Calcul... #powershell #ediscovery #microsoft-365 #compliance #security

Introduction

L'eDiscovery Microsoft 365 permet d'extraire le contenu d'une boîte mail ou d'un OneDrive à des fins légales, d'archivage ou d'investigation. Via le portail Purview, l'opération est manuelle et chronophage. Le module Faitza_Ediscovery.ps1 l'automatise de bout en bout : création du cas, lancement de la recherche, attente de completion, déclenchement de l'export et téléchargement du résultat.

Toutes les opérations s'appuient sur les cmdlets du Security & Compliance Center PowerShell, accessibles via Connect-IPPSSession. Ce n'est pas Exchange Online — c'est un endpoint distinct qui nécessite des permissions spécifiques.

Prérequis

Le compte de service doit être membre du groupe de rôles eDiscovery Manager dans Microsoft Purview. Le module ExchangeOnlineManagement (v3+) est requis pour Connect-IPPSSession. Installez-le avec Install-Module ExchangeOnlineManagement.

# Connexion au Security & Compliance Center
# (distinct de Connect-ExchangeOnline)
Connect-IPPSSession -UserPrincipalName [email protected]

# Connexion non-interactive (certificat)
Connect-IPPSSession `
    -AppId                "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
    -CertificateThumbprint "ABCDEF1234567890ABCDEF1234567890ABCDEF12" `
    -Organization         "contoso.onmicrosoft.com"

# Vérifier que les cmdlets Compliance sont disponibles
Get-Command -Noun ComplianceCase | Select-Object Name

Cas d'usage : départ collaborateur

Le scénario typique est le départ d'un collaborateur : avant de supprimer son compte, le département juridique ou RH demande une archive complète de sa boîte mail et/ou de son OneDrive. L'eDiscovery est le seul mécanisme M365 qui permet d'exporter en PST de façon légalement défendable, avec une chaîne de traçabilité (cas numéroté, horodatage, opérateur identifié).

Workflow séquentiel obligatoire

Les étapes ne peuvent pas être parallélisées : chaque phase dépend de la précédente. Le workflow complet est : Créer le cas → Créer la recherche → Démarrer la recherche → Attendre la completion → Créer l'action d'export → Attendre l'export → Télécharger → Nettoyer.

Le module expose six fonctions qui correspondent exactement à ces étapes. Elles peuvent être appelées individuellement pour reprendre un workflow interrompu, ou enchaînées dans un script d'orchestration.

Export boîte mail — New-Faitza_Ediscovery_PST

New-Faitza_Ediscovery_PST crée un cas eDiscovery et une recherche de contenu ciblant exclusivement la boîte mail d'un utilisateur. Elle retourne l'objet cas et l'objet recherche pour les étapes suivantes.

function New-Faitza_Ediscovery_PST {
    <#
    .SYNOPSIS
        Crée un cas eDiscovery et une recherche de contenu sur la boîte mail d'un utilisateur.
    .PARAMETER UserUPN
        UPN de l'utilisateur cible (ex: [email protected]).
    .PARAMETER CasePrefix
        Préfixe du nom du cas (ex: "DEPART"). Le cas sera nommé "DEPART-jean.dupont-20250528".
    .OUTPUTS
        PSCustomObject avec CaseName, SearchName, UserUPN.
    #>
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory)][string]$UserUPN,
        [string]$CasePrefix = "EDISCOVERY",
        [switch]$show
    )

    begin {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)>>> New-Faitza_Ediscovery_PST <<<$($PSStyle.Reset)" }
        $dateStamp  = Get-Date -Format "yyyyMMdd"
        $userSlug   = ($UserUPN.Split("@")[0]).ToLower()
        $caseName   = "$CasePrefix-$userSlug-$dateStamp"
        $searchName = "Search-Mailbox-$userSlug-$dateStamp"
    }

    process {
        if (-not $PSCmdlet.ShouldProcess($UserUPN, "Créer cas eDiscovery + recherche boîte mail")) { return }

        try {
            # 1. Créer le cas
            Write-Verbose "Création du cas : $caseName"
            $case = New-ComplianceCase -Name $caseName -CaseType eDiscovery
            Write-Host "[OK] Cas créé : $caseName (Id: $($case.Identity))" -ForegroundColor Cyan

            # 2. Créer la recherche de contenu sur la boîte mail
            Write-Verbose "Création de la recherche : $searchName"
            $search = New-ComplianceSearch `
                -Name        $searchName `
                -Case        $caseName `
                -ExchangeLocation $UserUPN `
                -AllowNotFoundExchangeLocationsEnabled $false `
                -ContentMatchQuery "kind:email"   # Tous les emails, sans filtre de date

            Write-Host "[OK] Recherche créée : $searchName" -ForegroundColor Cyan

            # 3. Démarrer la recherche
            Write-Verbose "Démarrage de la recherche..."
            Start-ComplianceSearch -Identity $searchName
            Write-Host "[OK] Recherche démarrée." -ForegroundColor Green

            return [PSCustomObject]@{
                CaseName   = $caseName
                SearchName = $searchName
                UserUPN    = $UserUPN
                StartedAt  = (Get-Date -Format "o")
            }
        }
        catch {
            throw [System.Exception]::new("New-Faitza_Ediscovery_PST échoué : $_")
        }
    }

    end {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)<<< New-Faitza_Ediscovery_PST >>>$($PSStyle.Reset)" }
    }
}

# Appel
$ctx = New-Faitza_Ediscovery_PST -UserUPN "[email protected]" -CasePrefix "DEPART" -show
ContentMatchQuery

Le paramètre -ContentMatchQuery accepte la syntaxe KQL de Purview. Pour exporter l'intégralité de la boîte sans filtre, laissez-le vide ou utilisez "kind:email". Pour cibler une plage temporelle : "kind:email AND sent:2024-01-01..2025-01-01".

Export OneDrive — New-Faitza_Ediscovery_OneDrive

New-Faitza_Ediscovery_OneDrive cible le OneDrive de l'utilisateur plutôt que sa boîte mail. La structure est identique, mais -SharePointLocation remplace -ExchangeLocation. L'URL OneDrive suit le format https://tenant-my.sharepoint.com/personal/upn_sanitized.

function New-Faitza_Ediscovery_OneDrive {
    <#
    .SYNOPSIS
        Crée un cas eDiscovery et une recherche de contenu sur le OneDrive d'un utilisateur.
    .PARAMETER UserUPN
        UPN de l'utilisateur cible.
    .PARAMETER TenantName
        Nom du tenant sans .onmicrosoft.com (ex: "contoso").
    .PARAMETER CasePrefix
        Préfixe du nom du cas.
    #>
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory)][string]$UserUPN,
        [Parameter(Mandatory)][string]$TenantName,
        [string]$CasePrefix = "EDISCOVERY",
        [switch]$show
    )

    begin {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)>>> New-Faitza_Ediscovery_OneDrive <<<$($PSStyle.Reset)" }
        $dateStamp  = Get-Date -Format "yyyyMMdd"
        $userSlug   = ($UserUPN.Split("@")[0]).ToLower()
        $caseName   = "$CasePrefix-OD-$userSlug-$dateStamp"
        $searchName = "Search-OneDrive-$userSlug-$dateStamp"

        # Construire l'URL OneDrive : [email protected] → jean_dupont_contoso_com
        $oneDriveSlug = $UserUPN -replace '[@.]', '_'
        $oneDriveUrl  = "https://$TenantName-my.sharepoint.com/personal/$oneDriveSlug"
    }

    process {
        if (-not $PSCmdlet.ShouldProcess($UserUPN, "Créer cas eDiscovery + recherche OneDrive")) { return }

        try {
            Write-Verbose "URL OneDrive cible : $oneDriveUrl"

            # Créer le cas
            $case = New-ComplianceCase -Name $caseName -CaseType eDiscovery
            Write-Host "[OK] Cas créé : $caseName" -ForegroundColor Cyan

            # Créer la recherche sur SharePoint/OneDrive
            $search = New-ComplianceSearch `
                -Name               $searchName `
                -Case               $caseName `
                -SharePointLocation $oneDriveUrl `
                -AllowNotFoundExchangeLocationsEnabled $false

            # Démarrer immédiatement
            Start-ComplianceSearch -Identity $searchName
            Write-Host "[OK] Recherche OneDrive démarrée : $searchName" -ForegroundColor Green

            return [PSCustomObject]@{
                CaseName    = $caseName
                SearchName  = $searchName
                UserUPN     = $UserUPN
                OneDriveUrl = $oneDriveUrl
                StartedAt   = (Get-Date -Format "o")
            }
        }
        catch {
            throw [System.Exception]::new("New-Faitza_Ediscovery_OneDrive échoué : $_")
        }
    }

    end {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)<<< New-Faitza_Ediscovery_OneDrive >>>$($PSStyle.Reset)" }
    }
}

# Appel
$ctxOD = New-Faitza_Ediscovery_OneDrive `
    -UserUPN     "[email protected]" `
    -TenantName  "contoso" `
    -CasePrefix  "DEPART" `
    -show
URL OneDrive sensible à la casse

L'URL OneDrive générée doit correspondre exactement à l'URL réelle du site. Si l'UPN contient des caractères spéciaux (tirets, points multiples), la sanitisation peut différer. Vérifiez l'URL via Get-SPOSite -IncludePersonalSite $true -Filter "Owner -eq '$UserUPN'" avant de l'utiliser dans la recherche.

Attente & polling — Wait-Faitza_Ediscovery_Case

Une recherche de contenu peut prendre de quelques secondes à plusieurs heures selon le volume de données. Wait-Faitza_Ediscovery_Case boucle sur Get-ComplianceSearch jusqu'à ce que le statut soit Completed. Elle lève une exception si le délai maximum est dépassé.

function Wait-Faitza_Ediscovery_Case {
    <#
    .SYNOPSIS
        Attend la completion d'une recherche eDiscovery avec polling configurable.
    .PARAMETER SearchName
        Nom de la recherche de contenu (ComplianceSearch).
    .PARAMETER PollIntervalSeconds
        Intervalle entre deux vérifications de statut. Défaut : 30 secondes.
    .PARAMETER TimeoutMinutes
        Délai maximum d'attente avant exception. Défaut : 120 minutes.
    .OUTPUTS
        L'objet ComplianceSearch final (Completed).
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$SearchName,
        [int]$PollIntervalSeconds = 30,
        [int]$TimeoutMinutes      = 120,
        [switch]$show
    )

    begin {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)>>> Wait-Faitza_Ediscovery_Case <<<$($PSStyle.Reset)" }
        $deadline  = (Get-Date).AddMinutes($TimeoutMinutes)
        $iteration = 0
    }

    process {
        Write-Verbose "Polling '$SearchName' toutes les $PollIntervalSeconds s (timeout: $TimeoutMinutes min)..."

        while ((Get-Date) -lt $deadline) {
            $iteration++
            $search = Get-ComplianceSearch -Identity $SearchName -ErrorAction Stop

            $status    = $search.Status
            $items     = $search.Items
            $sizeBytes = $search.Size

            $sizeMb = if ($sizeBytes -gt 0) { [math]::Round($sizeBytes / 1MB, 1) } else { 0 }

            Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Iteration $iteration — Statut : $status | Items : $items | Taille : $sizeMb MB" -ForegroundColor DarkCyan

            if ($status -eq "Completed") {
                Write-Host "[OK] Recherche terminée : $items éléments ($sizeMb MB)" -ForegroundColor Green
                return $search
            }

            if ($status -in @("Failed", "Stopped")) {
                throw [System.Exception]::new("La recherche '$SearchName' a échoué avec le statut : $status")
            }

            # Statuts intermédiaires attendus : Starting, InProgress, NotStarted
            Start-Sleep -Seconds $PollIntervalSeconds
        }

        throw [System.TimeoutException]::new(
            "Timeout : la recherche '$SearchName' n'a pas terminé dans les $TimeoutMinutes minutes imparties."
        )
    }

    end {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)<<< Wait-Faitza_Ediscovery_Case >>>$($PSStyle.Reset)" }
    }
}

# Attendre la completion avec un polling toutes les 60 secondes
$completedSearch = Wait-Faitza_Ediscovery_Case `
    -SearchName          "Search-Mailbox-jean.dupont-20250528" `
    -PollIntervalSeconds 60 `
    -TimeoutMinutes      180 `
    -show
Statuts possibles

Les valeurs de Status retournées par Get-ComplianceSearch sont : NotStarted, Starting, InProgress, Completed, Failed, Stopped. Seul Completed garantit que l'export peut être déclenché sans erreur.

Déclencher & télécharger — Export-Faitza_Ediscovery_Case & Save-Faitza_Ediscovery_Case

Une fois la recherche terminée, Export-Faitza_Ediscovery_Case crée l'action d'export (format PST ou fichier individuel). Save-Faitza_Ediscovery_Case attend la fin de la préparation de l'export et récupère le lien de téléchargement.

function Export-Faitza_Ediscovery_Case {
    <#
    .SYNOPSIS
        Déclenche l'action d'export sur une recherche eDiscovery terminée.
    .PARAMETER SearchName
        Nom de la ComplianceSearch (statut Completed requis).
    .PARAMETER ExportFormat
        FitIntoOnePST (un seul PST) ou IndividualMessage (fichiers .msg séparés).
        Défaut : FitIntoOnePST.
    #>
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory)][string]$SearchName,
        [ValidateSet("FitIntoOnePST", "PerSourcePST", "IndividualMessage")]
        [string]$ExportFormat = "FitIntoOnePST",
        [switch]$show
    )

    begin {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)>>> Export-Faitza_Ediscovery_Case <<<$($PSStyle.Reset)" }
        $actionName = "Export-$SearchName"
    }

    process {
        if (-not $PSCmdlet.ShouldProcess($SearchName, "Créer action d'export eDiscovery")) { return }

        try {
            $action = New-ComplianceSearchAction `
                -SearchName  $SearchName `
                -Export `
                -Format      $ExportFormat `
                -ExchangeArchiveFormat $ExportFormat `
                -Scope       IndexedItemsOnly   # Exclure les éléments non indexés (corrompu, chiffré)

            Write-Host "[OK] Action d'export créée : $($action.Name)" -ForegroundColor Cyan

            return [PSCustomObject]@{
                ActionName = $action.Name
                SearchName = $SearchName
                Format     = $ExportFormat
                CreatedAt  = (Get-Date -Format "o")
            }
        }
        catch {
            throw [System.Exception]::new("Export-Faitza_Ediscovery_Case échoué : $_")
        }
    }

    end {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)<<< Export-Faitza_Ediscovery_Case >>>$($PSStyle.Reset)" }
    }
}

function Save-Faitza_Ediscovery_Case {
    <#
    .SYNOPSIS
        Attend la completion de l'export et retourne l'URL + la clé de téléchargement.
    .PARAMETER ActionName
        Nom de la ComplianceSearchAction d'export.
    .PARAMETER PollIntervalSeconds
        Intervalle de polling. Défaut : 30 s.
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$ActionName,
        [int]$PollIntervalSeconds = 30,
        [int]$TimeoutMinutes      = 60,
        [switch]$show
    )

    begin {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)>>> Save-Faitza_Ediscovery_Case <<<$($PSStyle.Reset)" }
        $deadline = (Get-Date).AddMinutes($TimeoutMinutes)
    }

    process {
        while ((Get-Date) -lt $deadline) {
            $action = Get-ComplianceSearchAction -Identity $ActionName -ErrorAction Stop
            $status = $action.Status

            Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Export statut : $status" -ForegroundColor DarkCyan

            if ($status -eq "Completed") {
                # Extraire l'URL et la clé SAS depuis les résultats de l'action
                $results = $action.Results
                $exportUrl = ($results -split ";") |
                    Where-Object { $_ -match "Container url:" } |
                    ForEach-Object { ($_ -split "Container url:")[1].Trim() }
                $sasKey = ($results -split ";") |
                    Where-Object { $_ -match "SAS token:" } |
                    ForEach-Object { ($_ -split "SAS token:")[1].Trim() }

                Write-Host "[OK] Export prêt au téléchargement." -ForegroundColor Green
                Write-Host "     URL : $exportUrl" -ForegroundColor Gray

                return [PSCustomObject]@{
                    ActionName = $ActionName
                    ExportUrl  = $exportUrl
                    SasToken   = $sasKey
                    CompletedAt = (Get-Date -Format "o")
                }
            }

            if ($status -in @("Failed", "Stopped")) {
                throw [System.Exception]::new("L'export '$ActionName' a échoué : $status")
            }

            Start-Sleep -Seconds $PollIntervalSeconds
        }

        throw [System.TimeoutException]::new("Timeout : l'export '$ActionName' n'a pas terminé dans les $TimeoutMinutes minutes.")
    }

    end {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)<<< Save-Faitza_Ediscovery_Case >>>$($PSStyle.Reset)" }
    }
}

# Workflow complet — étapes 4 et 5
$exportCtx = Export-Faitza_Ediscovery_Case -SearchName "Search-Mailbox-jean.dupont-20250528" -show
$dlInfo    = Save-Faitza_Ediscovery_Case   -ActionName $exportCtx.ActionName -show

# À ce stade, $dlInfo.ExportUrl et $dlInfo.SasToken permettent de télécharger le PST
# via l'outil Microsoft eDiscovery Export Tool (GUI) ou via AzCopy :
# azcopy copy "$($dlInfo.ExportUrl)?$($dlInfo.SasToken)" "C:\Exports\" --recursive
eDiscovery Export Tool

Le téléchargement du PST final nécessite l'eDiscovery Export Tool, un client Windows téléchargeable depuis le portail Purview. Il ne peut pas être invoqué en ligne de commande pure. L'alternative scriptable est d'utiliser AzCopy avec l'URL SAS retournée par Get-ComplianceSearchAction, mais cette URL expire après 7 jours.

Nettoyage — Remove-Faitza_Ediscovery_Case

Après téléchargement, le cas doit être fermé et supprimé. Un cas eDiscovery actif maintient un hold implicite sur les ressources Purview. Remove-Faitza_Ediscovery_Case supprime d'abord la recherche et l'action d'export associées, puis ferme et supprime le cas.

function Remove-Faitza_Ediscovery_Case {
    <#
    .SYNOPSIS
        Supprime un cas eDiscovery et tous ses artefacts associés (recherche, actions d'export).
    .PARAMETER CaseName
        Nom du cas eDiscovery à supprimer.
    .PARAMETER SearchName
        Nom de la ComplianceSearch associée.
    #>
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "High")]
    param(
        [Parameter(Mandatory)][string]$CaseName,
        [Parameter(Mandatory)][string]$SearchName,
        [switch]$show
    )

    begin {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)>>> Remove-Faitza_Ediscovery_Case <<<$($PSStyle.Reset)" }
    }

    process {
        if (-not $PSCmdlet.ShouldProcess($CaseName, "Supprimer cas eDiscovery et artefacts")) { return }

        try {
            # 1. Supprimer les actions d'export liées à la recherche
            $actions = Get-ComplianceSearchAction -SearchName $SearchName -ErrorAction SilentlyContinue
            foreach ($action in $actions) {
                Write-Verbose "Suppression de l'action d'export : $($action.Name)"
                Remove-ComplianceSearchAction -Identity $action.Name -Confirm:$false
                Write-Host "  [OK] Action supprimée : $($action.Name)" -ForegroundColor Gray
            }

            # 2. Supprimer la recherche de contenu
            Write-Verbose "Suppression de la recherche : $SearchName"
            Remove-ComplianceSearch -Identity $SearchName -Confirm:$false
            Write-Host "  [OK] Recherche supprimée : $SearchName" -ForegroundColor Gray

            # 3. Fermer le cas (Status → Closed) avant de le supprimer
            Set-ComplianceCase -Identity $CaseName -Status Closed
            Write-Host "  [OK] Cas fermé : $CaseName" -ForegroundColor Gray

            # 4. Supprimer le cas
            Remove-ComplianceCase -Identity $CaseName -Confirm:$false
            Write-Host "[OK] Cas eDiscovery supprimé : $CaseName" -ForegroundColor Green
        }
        catch {
            throw [System.Exception]::new("Remove-Faitza_Ediscovery_Case échoué : $_")
        }
    }

    end {
        if ($show) { Write-Host "$($PSStyle.Background.Blue)<<< Remove-Faitza_Ediscovery_Case >>>$($PSStyle.Reset)" }
    }
}

# Nettoyage
Remove-Faitza_Ediscovery_Case `
    -CaseName   "DEPART-jean.dupont-20250528" `
    -SearchName "Search-Mailbox-jean.dupont-20250528" `
    -Confirm:$false `
    -show

Pièges classiques

# ─── Piège 1 : Connect-ExchangeOnline ≠ Connect-IPPSSession ──────────────────
# Les cmdlets New-ComplianceCase, New-ComplianceSearch etc. ne sont disponibles
# qu'après Connect-IPPSSession. Connect-ExchangeOnline ne suffit pas.
Connect-IPPSSession -Organization "contoso.onmicrosoft.com"

# ─── Piège 2 : Lancer l'export avant Completed ───────────────────────────────
# New-ComplianceSearchAction sur une recherche en statut InProgress renvoie :
# "The search is not in a state that allows export."
# Toujours appeler Wait-Faitza_Ediscovery_Case avant Export-Faitza_Ediscovery_Case.

# ─── Piège 3 : Noms de cas dupliqués ─────────────────────────────────────────
# Les noms de cas doivent être uniques dans le tenant. Si tu relances le script
# le même jour pour le même utilisateur, le nom sera identique et New-ComplianceCase
# échoue avec "The name is already in use." Ajoutez l'heure ou un GUID au suffix.
$caseName = "DEPART-$userSlug-$(Get-Date -Format 'yyyyMMdd-HHmm')"

# ─── Piège 4 : Scope des éléments non indexés ────────────────────────────────
# Par défaut, New-ComplianceSearchAction -Export inclut les éléments non indexés
# (fichiers chiffrés, corrompus). Cela peut faire échouer le package PST.
# Utilisez -Scope IndexedItemsOnly sauf besoin légal spécifique.

# ─── Piège 5 : URL SAS expirée ───────────────────────────────────────────────
# L'URL de téléchargement retournée par Get-ComplianceSearchAction expire après
# 7 jours. Passé ce délai, il faut recréer l'action d'export (sans recréer le cas).
$expiredAction = "Export-Search-Mailbox-jean.dupont-20250528_Export"
Remove-ComplianceSearchAction -Identity $expiredAction -Confirm:$false
New-ComplianceSearchAction -SearchName "Search-Mailbox-jean.dupont-20250528" -Export -Format FitIntoOnePST

# ─── Piège 6 : Fermer le cas avant de le supprimer ───────────────────────────
# Remove-ComplianceCase sur un cas en statut "Active" échoue.
# Il faut d'abord Set-ComplianceCase -Status Closed, attendre quelques secondes,
# puis Remove-ComplianceCase.
Set-ComplianceCase   -Identity $caseName -Status Closed
Start-Sleep -Seconds 5
Remove-ComplianceCase -Identity $caseName -Confirm:$false
Permissions minimales requises

Le compte exécutant ces cmdlets doit être membre du groupe de rôles eDiscovery Manager dans le portail Microsoft Purview. Pour les exports, le rôle Compliance Administrator peut être nécessaire selon la configuration du tenant. Vérifiez avec Get-RoleGroupMember -Identity "eDiscovery Manager" depuis une session IPPSSession.

Latence de provisioning

Immédiatement après New-ComplianceCase, les cmdlets New-ComplianceSearch peuvent renvoyer une erreur indiquant que le cas n'existe pas encore. C'est un problème de propagation dans l'infrastructure Purview. Ajoutez un Start-Sleep -Seconds 10 entre la création du cas et la création de la recherche si vous rencontrez ce comportement.

// Commentaires

Aucun commentaire pour l'instant.