> For the complete documentation index, see [llms.txt](https://docs.realmjoin.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.realmjoin.com/fr/dev-reference/report-functions/publish-rjrbfilestostoragecontainer.md).

# Publish-RjRbFilesToStorageContainer

Téléversez des fichiers locaux vers un conteneur Azure Storage depuis des runbooks Azure Automation et renvoyez des liens de téléchargement SAS à durée limitée.

## Aperçu

`Publish-RjRbFilesToStorageContainer` est l'assistant standard pour la livraison des fichiers de rapport (CSV, XLSX, ZIP, …) depuis les runbooks de reporting RealmJoin via Azure Blob Storage. Il téléverse un ou plusieurs fichiers locaux vers un conteneur cible et renvoie pour chaque blob un lien de téléchargement SAS à durée limitée, adapté à une inclusion dans des e-mails de rapport, des messages Teams ou des sorties de runbook.

Caractéristiques clés :

* **Aucun `Az.Storage` dépendance** — les opérations sur les blobs sont effectuées directement via l'API REST Azure Storage (création du conteneur, téléversement, génération de SAS Token). Cela élimine le conflit d'assembly bien connu entre `Az.Storage` et `ExchangeOnlineManagement` qui apparaît dans les runbooks de reporting mixtes.
* **Connexion automatique** — si aucun `contexte Az` n'est actif, la fonction appelle de façon transparente `Connect-RjRbAzAccount`. Un `-SubscriptionId` bascule le contexte avant toute opération de stockage.
* **Conteneur créé automatiquement** — si le conteneur cible n'existe pas encore, il est créé à la volée ; un conteneur existant (HTTP 409) est considéré comme un succès.
* **Téléversements basés sur HttpClient** — utilise `System.Net.Http.HttpClient` directement car le `Invoke-RestMethod` intercepteur d'Azure Automation supprime les en-têtes personnalisés requis (`x-ms-blob-type`) avec les corps binaires.
* **Liens SAS en lecture seule** — chaque URL renvoyée est signée avec la clé du compte de stockage, limitée à un seul blob, uniquement en HTTPS et valide pendant `LinkExpiryDays` jours (par défaut 6).

Les paramètres centraux de stockage (groupe de ressources, nom du compte, durée d'expiration, préfixe de nom de blob) consommés par un runbook typique se trouvent dans le JSON de personnalisation RealmJoin et sont documentés dans [Paramètres de rapport de runbook — remise via Storage Account](/fr/automatisation/runbooks/runbook-report-settings.md#storage-account-delivery). Ce document se concentre sur l'appel de la fonction depuis un runbook.

## Prérequis

### Azure Storage Account

Un Azure Storage Account existant (généraliste v2 recommandé) est requis. Le conteneur cible n'a pas besoin d'exister au préalable — il est créé automatiquement lors de la première utilisation.

### Azure RBAC sur le Storage Account

L'identité managée du compte Automation (ou le Service Principal utilisé par le runbook) a besoin des autorisations suivantes sur le Storage Account :

| Action                                              | Requis pour                                                                                   |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `Microsoft.Storage/storageAccounts/read`            | Lecture du Storage Account                                                                    |
| `Microsoft.Storage/storageAccounts/listKeys/action` | Récupération de la clé du compte utilisée pour la signature SharedKey et la génération de SAS |

Attribuez le rôle intégré **Reader and Data Access** sur le Storage Account : c'est le plus petit rôle intégré qui couvre les deux. La création du conteneur, le téléversement et la génération de SAS sont autorisés avec la clé du compte et ne nécessitent aucune autorisation Azure RBAC supplémentaire. **Storage Account Contributor** fonctionne également, mais autorise en plus la gestion et la suppression du Storage Account. **Storage Blob Data Contributor** seul *n'est pas* suffisant, car la fonction signe les requêtes avec la clé du compte plutôt qu'en utilisant des opérations de blob adossées à AAD.

Comme la fonction s'authentifie avec la clé du compte, l'accès par clé partagée doit être autorisé sur le Storage Account (`allowSharedKeyAccess` ne doit pas être `false`). La clé accorde l'accès à toutes les données du Storage Account, donc un Storage Account dédié aux rapports est recommandé.

### Connexion au module

La fonction nécessite le module `Az.Accounts` dans l'environnement du runbook (`Get-AzContext`, `Set-AzContext`, `Connect-AzAccount`, `Invoke-AzRestMethod`). Déclarez-le explicitement dans le runbook consommateur :

```powershell
#Requires -Modules @{ModuleName = "RealmJoin.RunbookHelper"; ModuleVersion = "0.8.6" }
#Requires -Modules @{ModuleName = "Az.Accounts"; ModuleVersion = "5.3.4" }
```

Si `Az.Accounts` n'est pas disponible à l'exécution, la fonction échoue rapidement avec un message d'erreur clair — elle vérifie la présence de `Get-AzContext` en amont et lève *"Publish-RjRbFilesToStorageContainer requires the 'Az.Accounts' module. Add #Requires -Modules @{ModuleName = 'Az.Accounts'; ModuleVersion = '5.3.4'} to the calling runbook."* avant qu'un appel Azure ne soit effectué.

> **Pourquoi `Az.Accounts` n'est-il pas déclaré comme une entrée `RequiredModules` dans `RealmJoin.RunbookHelper.psd1`?**
>
> `Az.Accounts` est intentionnellement répertorié uniquement sous `ExternalModuleDependencies` (informatif) et *n'est pas* sous `RequiredModules` (appliqué au moment de `Import-Module` ) :
>
> * **On ne paie que ce que l'on utilise.** De nombreux runbooks utilisent seulement des assistants basés sur Graph (par ex. `Send-RjRbReportEmail` sans `-UseNativeGraphRequest`ou `Invoke-RjRbRestMethodGraph`) et n'appellent jamais de cmdlet Az.\*. Promouvoir `Az.Accounts` à `RequiredModules` forcerait chaque runbook consommateur à embarquer le module, même lorsque rien dans son chemin de code n'en a besoin — augmentant sensiblement le temps de démarrage à froid dans Azure Automation.
> * **Éviter les conflits de versions.** Une `RequiredModules` contrainte stricte déclenche la résolution automatique à l'import et peut entraîner une `Az.Accounts` version spécifique qui entre en conflit avec celle que le runbook lui-même verrouille (les sous-modules Az.\* sont notoirement sensibles aux versions). Laisser le runbook déclarer ses propres `#Requires -Modules` garde le choix de version côté appelant.
> * **Autorité par runbook.** Dans Azure Automation, l'endroit canonique pour déclarer les exigences de modules est au niveau du runbook via `#Requires`, et non au niveau du module d'assistance. Le module d'assistance expose la dépendance à titre informatif (via `ExternalModuleDependencies` dans le manifeste) et via le contrôle d'exécution ci-dessus, de sorte qu'une mauvaise configuration échoue bruyamment avec un message exploitable plutôt que de masquer silencieusement un conflit de version.

`Az.Storage` est **n'est pas** requis et ne doit pas être importé dans le même runbook afin d'éviter le conflit d'assembly mentionné ci-dessus.

## Démarrage rapide

L'appel minimal viable nécessite le ou les chemins de fichiers locaux, le nom du conteneur, le groupe de ressources et le nom du Storage Account :

```powershell
$csvPath = Join-Path $env:TEMP 'devices.csv'
$exportData | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8

$results = Publish-RjRbFilesToStorageContainer `
    -FilePaths          $csvPath `
    -ContainerName      'reports' `
    -ResourceGroupName  'rg-reports' `
    -StorageAccountName 'stcontosoreports'

$results | Format-Table BlobName, EndTime, SASLink
```

Cela téléverse `devices.csv` dans le `conteneur reports` dans `stcontosoreports` et renvoie un objet avec le nom du blob, l'horodatage d'expiration du SAS et une URL de téléchargement prête à partager, valide par défaut pendant 6 jours.

## Paramètres

### Obligatoire

| Paramètre            | Type       | Description                                                                                                                                                                                                                                                                                                       |
| -------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FilePaths`          | `string[]` | Un ou plusieurs chemins de fichiers locaux à téléverser. Chaque chemin doit pointer vers un fichier existant (`Test-Path -PathType Leaf`); la fonction lève une erreur immédiatement si une entrée est manquante.                                                                                                 |
| `ContainerName`      | `string`   | Conteneur blob cible. Créé automatiquement s'il n'existe pas. Doit respecter les règles de nommage des conteneurs Azure (minuscules, 3 à 63 caractères, alphanumériques + tiret). Le nom du conteneur est une *décision propre à chaque runbook* et est défini dans le runbook, pas dans les paramètres centraux. |
| `ResourceGroupName`  | `string`   | Groupe de ressources qui contient le Storage Account. Généralement relié au paramètre central `RJReport.StorageAccount.ResourceGroup`.                                                                                                                                                                            |
| `StorageAccountName` | `string`   | Nom du Azure Storage Account. Généralement relié au paramètre central `RJReport.StorageAccount.StorageAccountName`.                                                                                                                                                                                               |

### Facultatif

| Paramètre           | Type     | Par défaut      | Description                                                                                                                                                                                                                                  |
| ------------------- | -------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SubscriptionId`    | `string` | contexte actuel | Abonnement Azure qui héberge le Storage Account. S'il est fourni, `Set-AzContext -Subscription` est appelé avant toute opération de stockage. Omis pour utiliser le `contexte Az` contexte.                                                  |
| `LinkExpiryDays`    | `int`    | `6`             | Validité du lien SAS en jours. Validée à `[1, 3650]`. Le même horodatage d'expiration est appliqué à tous les blobs d'un même appel. Généralement relié au paramètre central `RJReport.StorageAccount.LinkExpiryDays`.                       |
| `AddBlobNamePrefix` | `bool`   | `$false`        | Lorsque `$true`, les noms de blob sont préfixés par `yyyyMMdd-HHmmss-` (horodatage de `Get-Date` au moment du téléversement) pour éviter les écrasements lors d'exécutions répétées. Le nom de fichier d'origine est conservé comme suffixe. |

> **Remarque :** Le mappage entre ces paramètres et le JSON de personnalisation RealmJoin central (y compris les valeurs par défaut recommandées) est documenté dans [Paramètres de rapport de runbook — remise via Storage Account](/fr/automatisation/runbooks/runbook-report-settings.md#storage-account-delivery).

## Exemples d'utilisation

### Modèle de runbook recommandé

Il s'agit du modèle canonique utilisé par les runbooks de reporting. La configuration de stockage est récupérée depuis la personnalisation centrale RealmJoin via `Use-RJInterface -Type Setting`, le conteneur est codé en dur par runbook, et une configuration manquante provoque l'arrêt du runbook avec un message exploitable :

```powershell
#Requires -Modules @{ModuleName = "RealmJoin.RunbookHelper"; ModuleVersion = "0.8.6" }
#Requires -Modules @{ModuleName = "Az.Accounts"; ModuleVersion = "5.3.4" }

param(
    [string] $ContainerName = "my-runbook-output",

    [ValidateScript( { Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process; Use-RJInterface -Type Setting -Attribute "RJReport.StorageAccount.ResourceGroup" } )]
    [string] $ResourceGroupName,

    [ValidateScript( { Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process; Use-RJInterface -Type Setting -Attribute "RJReport.StorageAccount.StorageAccountName" } )]
    [string] $StorageAccountName,

    [ValidateScript( { Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process; Use-RJInterface -Type Setting -Attribute "RJReport.StorageAccount.LinkExpiryDays" } )]
    [ValidateRange(1, 3650)]
    [int] $LinkExpiryDays = 6
)

Connect-RjRbAzAccount

if ((-not $ResourceGroupName) -or (-not $StorageAccountName)) {
    "## Pour exporter vers un Storage Account, veuillez utiliser RJ Runbooks Customization"
    "## ( https://portal.realmjoin.com/settings/runbooks-customizations ) pour configurer :"
    "##   - RJReport.StorageAccount.ResourceGroup"
    "##   - RJReport.StorageAccount.StorageAccountName"
    throw "Configuration du Storage Account manquante."
}

# … produire le fichier d'export …
$exportPath = "myReport.csv"

$uploadResults = Publish-RjRbFilesToStorageContainer `
    -FilePaths          @($exportPath) `
    -ContainerName      $ContainerName `
    -ResourceGroupName  $ResourceGroupName `
    -StorageAccountName $StorageAccountName `
    -LinkExpiryDays     $LinkExpiryDays `
    -AddBlobNamePrefix  $true

$uploadResult = $uploadResults[0]
"## Export créé."
"## Expiration du lien : $($uploadResult.EndTime)"
$uploadResult.SASLink | Out-String
```

Quelques conventions à conserver lors de l'adoption de ce modèle :

* Les trois paramètres centraux (`ResourceGroup`, `StorageAccountName`, `LinkExpiryDays`) sont exposés comme paramètres du runbook reliés via `Use-RJInterface -Type Setting`, mais généralement *masqués* dans la personnalisation du runbook (`"Hide": true`) afin que les utilisateurs finaux ne les voient jamais.
* Le nom du conteneur est codé en dur par runbook (souvent via une valeur par défaut de `param` ) afin que les politiques de cycle de vie et les contrôles d'accès puissent être ajustés par type d'export — il ne s'agit volontairement pas *n'est pas* d'un paramètre central.
* `AddBlobNamePrefix $true` est la valeur par défaut sûre pour les exportations périodiques qui produisent à chaque exécution un nom de fichier fixe.
* La fonction est appelée à l'intérieur du bloc principal du runbook `try { … } catch { throw $_ } finally { Disconnect-AzAccount … }` afin que les échecs partiels remontent au job Automation et que le contexte Az soit libéré même en cas de succès.

### Plusieurs fichiers dans un seul appel

`FilePaths` accepte un tableau ; chaque fichier est téléversé séquentiellement et un objet résultat est renvoyé pour chaque blob téléversé.

```powershell
$results = Publish-RjRbFilesToStorageContainer `
    -FilePaths          @($csvPath, $xlsxPath) `
    -ContainerName      'reports' `
    -ResourceGroupName  $ResourceGroupName `
    -StorageAccountName $StorageAccountName

foreach ($r in $results) {
    "Téléversé $($r.BlobName) — téléchargement jusqu'au $($r.EndTime) : $($r.SASLink)"
}
```

### Durée de vie du lien personnalisée et abonnement explicite

```powershell
Publish-RjRbFilesToStorageContainer `
    -FilePaths          $exportPaths `
    -ContainerName      'quarterly-reports' `
    -ResourceGroupName  $ResourceGroupName `
    -StorageAccountName $StorageAccountName `
    -SubscriptionId     '00000000-0000-0000-0000-000000000000' `
    -LinkExpiryDays     30
```

Utile lorsque le runbook couvre plusieurs abonnements, ou lorsque les destinataires en aval ont besoin d'une fenêtre plus longue que la valeur par défaut de 6 jours.

### En combinaison avec `Send-RjRbReportEmail`

Un schéma courant consiste à téléverser les données volumineuses dans un blob storage et à intégrer le lien SAS dans un e-mail de rapport, en gardant l'e-mail bien en dessous de la limite Graph de 4 Mo `sendMail` limite :

```powershell
$uploaded = Publish-RjRbFilesToStorageContainer `
    -FilePaths          $csvPath `
    -ContainerName      'reports' `
    -ResourceGroupName  $ResourceGroupName `
    -StorageAccountName $StorageAccountName `
    -AddBlobNamePrefix  $true

$linkLine = "[Télécharger {0}]({1}) (valide jusqu'au {2:yyyy-MM-dd HH:mm} UTC)" -f `
    $uploaded[0].BlobName, $uploaded[0].SASLink, $uploaded[0].EndTime.ToUniversalTime()

$reportMd = @"
# Inventaire des appareils

La liste complète des appareils est disponible en téléchargement :

$linkLine
"@

Send-RjRbReportEmail `
    -EmailFrom       $emailFrom `
    -EmailTo         'it-reports@contoso.com' `
    -Subject         "Device Inventory — $(Get-Date -Format 'yyyy-MM-dd')" `
    -MarkdownContent $reportMd
```

Voir [Send-RjRbReportEmail](/fr/dev-reference/report-functions/send-rjrbreportemail.md) pour la partie e-mail de ce modèle.

## Comportement et gestion des erreurs

### Validation préalable des fichiers

Avant qu'un appel Azure ne soit effectué, la fonction parcourt `FilePaths` et lève `Le fichier « <path> » est introuvable.` pour la première entrée manquante. Cela évite les téléversements partiels lorsque l'appelant a fait une faute de frappe.

### Résolution du contexte Azure

`Get-AzContext` est vérifié en premier. S'il n'y a pas de contexte ou si le contexte n'a pas de `Account` (par exemple, une exécution de runbook fraîche), la fonction appelle `Connect-RjRbAzAccount` pour authentifier l'identité managée. Si `-SubscriptionId` est fourni, `Set-AzContext -Subscription` est appelé ensuite.

### Création du conteneur

Le conteneur est créé avec une requête `PUT …?restype=container` :

* **HTTP 201** — conteneur créé.
* **HTTP 409** — le conteneur existe déjà ; traité comme un succès.
* **Tout autre statut** — la fonction lève `La création du conteneur a échoué (<status>) : <body>`. Un HTTP 403 avec `KeyBasedAuthenticationNotPermitted` signifie que l'accès par clé partagée est désactivé sur le Storage Account.

### Échecs de téléversement

Chaque fichier est téléversé via `HttpClient.SendAsync`. Un statut non satisfaisant termine l'appel avec `Échec du téléversement du blob (<status>) : <body>`, y compris l'erreur brute renvoyée par Azure Storage. Les fichiers précédemment téléversés dans le même appel restent dans le Storage Account — l'appelant peut vouloir envelopper l'appel dans un try/catch et exécuter un nettoyage si des téléversements partiels ne sont pas acceptables.

### Échecs de récupération de clé

`Invoke-AzRestMethod` est utilisé pour appeler le point de terminaison ARM `listKeys` . Si le code de réponse n'est pas 200, la fonction lève `Échec de la récupération des clés du Storage Account pour « <account> » dans le groupe de ressources « <rg> ». Statut : <status>`. Les causes les plus fréquentes sont :

* Absence de `Microsoft.Storage/storageAccounts/listKeys/action` sur l'identité managée.
* Contexte d'abonnement incorrect (à combiner avec `-SubscriptionId`).
* Faute de frappe dans `StorageAccountName` ou `ResourceGroupName`.
* Les paramètres centraux `RJReport.StorageAccount.ResourceGroup` / `RJReport.StorageAccount.StorageAccountName` non configuré — voir [Paramètres du rapport Runbook](/fr/automatisation/runbooks/runbook-report-settings.md#storage-account-delivery).

### Caractéristiques du SAS Token

Les jetons générés utilisent :

* `sv=2023-11-03` (version signée)
* `sr=b` (limité au blob)
* `sp=r` (lecture seule)
* `spr=https` (HTTPS uniquement)
* `st` défini à 5 minutes dans le passé (tolérance au décalage d’horloge) et `se` à `LinkExpiryDays` à partir de l’heure de l’appel.

Les jetons sont signés avec la clé du compte de stockage. **Toute personne disposant du lien peut télécharger le blob jusqu’à son expiration** — traitez l’URL SAS renvoyée comme un secret.

## Sorties

Chaque téléversement réussi produit un `PSCustomObject` avec ces propriétés :

| Propriété  | Type       | Description                                                                                                   |
| ---------- | ---------- | ------------------------------------------------------------------------------------------------------------- |
| `BlobName` | `string`   | Le nom final du blob dans le conteneur, y compris le préfixe d’horodatage si `AddBlobNamePrefix` est `$true`. |
| `EndTime`  | `datetime` | Expiration locale du SAS (également encodée dans l’URL en UTC).                                               |
| `SASLink`  | `string`   | URL de téléchargement HTTPS complète avec SAS Token intégré.                                                  |

Les résultats sont renvoyés dans le même ordre que `FilePaths`. Même lors du téléversement d’un seul fichier, la valeur renvoyée est un tableau — indexez-le (`$results[0]`) ou itérez avec `foreach` plutôt que de le traiter comme un scalaire.

## Voir aussi

* [Paramètres de rapport de runbook — remise via Storage Account](/fr/automatisation/runbooks/runbook-report-settings.md#storage-account-delivery) — configuration centrale du compte de stockage, de l’expiration du lien et du préfixe de nom de blob utilisés par les runbooks de reporting.
* [Send-RjRbReportEmail](/fr/dev-reference/report-functions/send-rjrbreportemail.md) — utilitaire compagnon pour envoyer des rapports par e-mail ; souvent combiné avec cette fonction afin de réduire la taille de la charge utile de l’e-mail.
* Microsoft Docs : [Autoriser avec une clé partagée](https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key) — schéma de signature utilisé par l’utilitaire.
* Microsoft Docs : [Créer un SAS de service](https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas) — format de SAS Token renvoyé dans `SASLink`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.realmjoin.com/fr/dev-reference/report-functions/publish-rjrbfilestostoragecontainer.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
