> 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/pt/dev-reference/report-functions/publish-rjrbfilestostoragecontainer.md).

# Publish-RjRbFilesToStorageContainer

## Visão geral

`Publish-RjRbFilesToStorageContainer` é o auxiliar padrão para entregar arquivos de relatório (CSV, XLSX, ZIP, …) em runbooks de relatório do RealmJoin por meio do Azure Blob Storage. Ele envia um ou mais arquivos locais para um contêiner de destino e retorna um link SAS de download com tempo limitado para cada blob, adequado para inclusão em e-mails de relatório, mensagens do Teams ou saídas do runbook.

Características principais:

* **Não `Az.Storage` dependência** — as operações de blob são realizadas diretamente contra a Azure Storage REST API (criação do contêiner, upload, geração de SAS token). Isso elimina o conhecido conflito de assembly entre `Az.Storage` e `ExchangeOnlineManagement` que surge em runbooks de relatório mistos.
* **Conexão automática** — se nenhum `Az` contexto estiver ativo, a função chama transparentemente `Connect-RjRbAzAccount`. Uma opção opcional `-SubscriptionId` altera o contexto antes de qualquer operação de armazenamento.
* **Contêiner criado automaticamente** — se o contêiner de destino ainda não existir, ele é criado automaticamente; um contêiner existente (HTTP 409) é tratado como sucesso.
* **Uploads baseados em HttpClient** — usa `System.Net.Http.HttpClient` diretamente porque o Azure Automation's `Invoke-RestMethod` interceptor do Azure Automation remove os cabeçalhos personalizados necessários (`x-ms-blob-type`) com corpos binários.
* **Links SAS somente leitura** — cada URL retornado é assinado com a chave da Storage Account, com escopo para um único blob, somente HTTPS e válido por `LinkExpiryDays` dias (padrão 6).

As configurações centrais de armazenamento (grupo de recursos, nome da conta, dias de expiração, prefixo do nome do blob) consumidas por um runbook típico ficam no JSON de personalização do RealmJoin e estão documentadas em [Configurações de Relatório do Runbook — Entrega da Storage Account](/pt/automacao/runbooks/runbook-report-settings.md#storage-account-delivery). Este documento se concentra em chamar a função a partir de um runbook.

## Pré-requisitos

### Azure Storage Account

É necessária uma Azure Storage Account existente (recomenda-se uso geral v2). O contêiner de destino não precisa existir antecipadamente — ele é criado automaticamente no primeiro uso.

### Azure RBAC na Storage Account

A identidade gerenciada da Automation Account (ou o Service Principal usado pelo runbook) precisa das seguintes permissões na Storage Account ou no respectivo grupo de recursos:

| Ação                                                | Necessário para                                                             |
| --------------------------------------------------- | --------------------------------------------------------------------------- |
| `Microsoft.Storage/storageAccounts/read`            | Ler a Storage Account                                                       |
| `Microsoft.Storage/storageAccounts/listKeys/action` | Recuperar a chave da conta usada para assinatura SharedKey e geração de SAS |

A função interna **Storage Account Contributor** cobre ambos. **Storage Blob Data Contributor** sozinho *não* é suficiente porque a função assina as solicitações com a chave da conta em vez de usar operações de blob com suporte do AAD.

### Conectividade do módulo

A função requer o `Az.Accounts` módulo no ambiente do runbook (`Get-AzContext`, `Set-AzContext`, `Connect-AzAccount`, `Invoke-AzRestMethod`). Declare-o explicitamente no runbook consumidor:

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

Se `Az.Accounts` não estiver disponível em tempo de execução, a função falha rapidamente com uma mensagem de erro clara — ela verifica `Get-AzContext` antecipadamente e lança *"Publish-RjRbFilesToStorageContainer requer o módulo 'Az.Accounts'. Adicione #Requires -Modules @{ModuleName = 'Az.Accounts'; ModuleVersion = '5.3.4'} ao runbook chamador."* antes que qualquer chamada ao Azure seja feita.

> **Por que não `Az.Accounts` declarado como uma `RequiredModules` entrada em `RealmJoin.RunbookHelper.psd1`?**
>
> `Az.Accounts` é intencionalmente listado apenas em `ExternalModuleDependencies` (informativo) e *não* sob `RequiredModules` (imposto em `Import-Module` tempo):
>
> * **Pague apenas pelo que usa.** Muitos runbooks consomem apenas auxiliares baseados em Graph (por exemplo, `Send-RjRbReportEmail` sem `-UseNativeGraphRequest`, ou `Invoke-RjRbRestMethodGraph`) e nunca tocam em nenhum cmdlet Az.\*. Promover `Az.Accounts` para `RequiredModules` forçaria todos os runbooks consumidores a empacotar o módulo mesmo quando nada em seu caminho de execução o exige — aumentando de forma mensurável o tempo de inicialização a frio no Azure Automation.
> * **Evite conflitos de versão.** Uma `RequiredModules` restrição rígida aciona a resolução automática no momento da importação e pode trazer uma `Az.Accounts` versão específica que conflita com o que o próprio runbook fixa (submódulos Az.\* são notoriamente sensíveis a versões). Permitir que o runbook declare seu próprio `#Requires -Modules` mantém a escolha da versão com o chamador.
> * **Autoridade por runbook.** No Azure Automation, o local canônico para declarar requisitos de módulo é no nível do runbook por meio de `#Requires`, não no nível do módulo auxiliar. O módulo auxiliar expõe a dependência de forma informativa (por meio de `ExternalModuleDependencies` no manifesto) e por meio da verificação de tempo de execução acima, de modo que uma configuração incorreta falhe de forma explícita com uma mensagem acionável, em vez de mascarar silenciosamente um conflito de versão.

`Az.Storage` é **não** necessário e não deve ser importado no mesmo runbook para evitar o conflito de assembly mencionado acima.

## Início rápido

A chamada mínima viável requer o(s) caminho(s) de arquivo local, o nome do contêiner, o grupo de recursos e o nome da 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
```

Isto envia `devices.csv` para o `reports` contêiner em `stcontosoreports` e retorna um objeto com o nome do blob, o carimbo de data/hora de expiração do SAS e uma URL de download pronta para compartilhar, válida por 6 dias por padrão.

## Parâmetros

### Obrigatório

| Parâmetro            | Tipo       | Descrição                                                                                                                                                                                                                                                                                       |
| -------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FilePaths`          | `string[]` | Um ou mais caminhos de arquivo locais para enviar. Cada caminho deve apontar para um arquivo existente (`Test-Path -PathType Leaf`); a função lança um erro antecipadamente se alguma entrada estiver ausente.                                                                                  |
| `ContainerName`      | `string`   | Contêiner de blob de destino. Criado automaticamente se não existir. Deve cumprir as regras de nomenclatura de contêiner do Azure (minúsculas, 3–63 caracteres, alfanumérico + hífen). O nome do contêiner é uma *por runbook* decisão e é definido no runbook, não nas configurações centrais. |
| `ResourceGroupName`  | `string`   | Grupo de recursos que contém a Storage Account. Normalmente vinculado à configuração central `RJReport.AzureStorage.ResourceGroup`.                                                                                                                                                             |
| `StorageAccountName` | `string`   | Nome da Azure Storage Account. Normalmente vinculado à configuração central `RJReport.AzureStorage.StorageAccountName`.                                                                                                                                                                         |

### Opcional

| Parâmetro           | Tipo     | Padrão         | Descrição                                                                                                                                                                                                                           |
| ------------------- | -------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SubscriptionId`    | `string` | contexto atual | Assinatura do Azure que hospeda a Storage Account. Se fornecida, `Set-AzContext -Subscription` é chamado antes de qualquer operação de armazenamento. Omita para usar o `Az` contexto.                                              |
| `LinkExpiryDays`    | `int`    | `6`            | Validade do link SAS em dias. Validado para `[1, 3650]`. O mesmo carimbo de expiração é aplicado a todos os blobs em uma única chamada. Normalmente vinculado à configuração central `RJReport.AzureStorage.LinkExpiryDays`.        |
| `AddBlobNamePrefix` | `bool`   | `$false`       | Quando `$true`, os nomes dos blobs recebem o prefixo `yyyyMMdd-HHmmss-` (carimbo de data/hora de `Get-Date` no momento do envio) para evitar sobrescritas em execuções repetidas. O nome original do arquivo é mantido como sufixo. |

> **Observação:** O mapeamento entre esses parâmetros e o JSON central de personalização do RealmJoin (incluindo os padrões recomendados) está documentado em [Configurações de Relatório do Runbook — Entrega da Storage Account](/pt/automacao/runbooks/runbook-report-settings.md#storage-account-delivery).

## Exemplos de uso

### Padrão de runbook recomendado

Este é o padrão canônico usado por runbooks de relatório. A configuração de armazenamento é obtida da personalização central do RealmJoin por meio de `Use-RJInterface -Type Setting`, o contêiner é codificado por runbook e uma configuração ausente faz com que o runbook seja interrompido com uma mensagem acionável:

```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.AzureStorage.ResourceGroup" } )]
    [string] $ResourceGroupName,

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

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

Connect-RjRbAzAccount

if ((-not $ResourceGroupName) -or (-not $StorageAccountName)) {
    "## Para exportar para uma Storage Account, use a personalização do RJ Runbooks"
    "## ( https://portal.realmjoin.com/settings/runbooks-customizations ) para configurar:"
    "##   - RJReport.AzureStorage.ResourceGroup"
    "##   - RJReport.AzureStorage.StorageAccountName"
    throw "Configuração da Storage Account ausente."
}

# … gerar o arquivo de exportação …
$exportPath = "myReport.csv"

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

$uploadResult = $uploadResults[0]
"## Exportação criada."
"## Expiração do link: $($uploadResult.EndTime)"
$uploadResult.SASLink | Out-String
```

Algumas convenções que valem a pena manter ao adotar esse padrão:

* As três configurações centrais (`ResourceGroup`, `StorageAccountName`, `LinkExpiryDays`) são expostas como parâmetros do runbook vinculados por meio de `Use-RJInterface -Type Setting`, mas normalmente *ocultas* na personalização do runbook (`"Hide": true`) para que os usuários finais nunca as vejam.
* O nome do contêiner é codificado por runbook (muitas vezes por meio de um `param` padrão) para que políticas de ciclo de vida e controles de acesso possam ser ajustados por tipo de exportação — ele intencionalmente não é *não* uma configuração central.
* `AddBlobNamePrefix $true` é o padrão seguro para exportações periódicas que produzem um nome de arquivo fixo a cada execução.
* A função é chamada dentro do bloco principal do runbook `try { … } catch { throw $_ } finally { Disconnect-AzAccount … }` para que falhas parciais propaguem-se para o trabalho da Automation e o contexto Az seja liberado mesmo em caso de sucesso.

### Vários arquivos em uma chamada

`FilePaths` aceita um array; cada arquivo é enviado sequencialmente e um objeto de resultado é retornado para cada blob enviado.

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

foreach ($r in $results) {
    "Enviado $($r.BlobName) — faça o download até $($r.EndTime): $($r.SASLink)"
}
```

### Duração personalizada do link e assinatura explícita

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

Útil quando o runbook abrange várias assinaturas ou quando os destinatários downstream precisam de uma janela maior que o padrão de 6 dias.

### Combinando com `Send-RjRbReportEmail`

Um padrão comum é enviar dados volumosos para o armazenamento de blobs e incorporar o link SAS em um e-mail de relatório, mantendo o e-mail bem abaixo do limite de 4 MB do Graph `sendMail` limite:

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

$linkLine = "[Baixar {0}]({1}) (válido até {2:yyyy-MM-dd HH:mm} UTC)" -f `
    $uploaded[0].BlobName, $uploaded[0].SASLink, $uploaded[0].EndTime.ToUniversalTime()

$reportMd = @"
# Inventário de dispositivos

A lista completa de dispositivos está disponível para download:

$linkLine
"@

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

Veja [Send-RjRbReportEmail](/pt/dev-reference/report-functions/send-rjrbreportemail.md) a parte de e-mail desse padrão.

## Comportamento e tratamento de erros

### Validação antecipada de arquivos

Antes que qualquer chamada ao Azure seja feita, a função percorre `FilePaths` e lança `Arquivo '<path>' não foi encontrado.` para a primeira entrada ausente. Isso evita uploads parciais quando o chamador passa um erro de digitação.

### Resolução do contexto Azure

`Get-AzContext` é verificado primeiro. Se não houver contexto ou o contexto não tiver `Conta` (por exemplo, uma execução nova do runbook), a função chama `Connect-RjRbAzAccount` para autenticar a identidade gerenciada. Se `-SubscriptionId` for fornecida, `Set-AzContext -Subscription` é invocado em seguida.

### Criação do contêiner

O contêiner é criado com uma `PUT …?restype=container` solicitação:

* **HTTP 201** — contêiner criado.
* **HTTP 409** — o contêiner já existe; tratado como sucesso.
* **Qualquer outro status** — a função lança `Falha ao criar o contêiner (<status>): <body>`.

### Falhas no envio

Cada arquivo é enviado por meio de `HttpClient.SendAsync`. Um status sem êxito encerra a chamada com `Falha no envio do blob (<status>): <body>`, incluindo o erro bruto retornado pelo Azure Storage. Arquivos anteriores que já tenham sido enviados na mesma chamada permanecem na Storage Account — o chamador pode querer envolver a chamada em um try/catch e executar limpeza se uploads parciais forem inaceitáveis.

### Falhas na recuperação da chave

`Invoke-AzRestMethod` é usado para chamar o ARM `listKeys` endpoint. Se o status da resposta for qualquer coisa diferente de 200, a função lança `Falha ao recuperar as chaves da Storage Account para '<account>' no grupo de recursos '<rg>'. Status: <status>`. As causas mais comuns são:

* Ausência de `Microsoft.Storage/storageAccounts/listKeys/action` na identidade gerenciada.
* Contexto de assinatura incorreto (combine com `-SubscriptionId`).
* Erro de digitação em `StorageAccountName` ou `ResourceGroupName`.
* As configurações centrais `RJReport.AzureStorage.ResourceGroup` / `RJReport.AzureStorage.StorageAccountName` não configuradas — veja [Configurações de relatório do runbook](/pt/automacao/runbooks/runbook-report-settings.md#storage-account-delivery).

### Características do token SAS

Os tokens gerados usam:

* `sv=2023-11-03` (versão assinada)
* `sr=b` (com escopo de blob)
* `sp=r` (somente leitura)
* `spr=https` (apenas HTTPS)
* `st` definido para 5 minutos no passado (tolerância ao desvio do relógio) e `se` para `LinkExpiryDays` a partir do momento da chamada.

Os tokens são assinados com a chave da conta de armazenamento. **Qualquer pessoa com o link pode descarregar o blob até à expiração** — trate o URL SAS devolvido como um segredo.

## Saídas

Cada carregamento bem-sucedido produz um `PSCustomObject` com estas propriedades:

| Propriedade | Tipo       | Descrição                                                                                             |
| ----------- | ---------- | ----------------------------------------------------------------------------------------------------- |
| `BlobName`  | `string`   | O nome final do blob no contentor, incluindo o prefixo de timestamp se `AddBlobNamePrefix` é `$true`. |
| `EndTime`   | `datetime` | Expiração do SAS em hora local (também codificada no URL como UTC).                                   |
| `SASLink`   | `string`   | URL HTTPS totalmente qualificado para descarregamento com token SAS incorporado.                      |

Os resultados são devolvidos na mesma ordem que `FilePaths`. Mesmo ao carregar um único ficheiro, o valor de retorno é uma matriz — aceda por índice (`$results[0]`) ou itere com `foreach` em vez de o tratar como um escalar.

## Ver também

* [Configurações de Relatório do Runbook — Entrega da Storage Account](/pt/automacao/runbooks/runbook-report-settings.md#storage-account-delivery) — configuração central da conta de armazenamento, da expiração do link e do prefixo do nome do blob usado pelos runbooks de relatórios.
* [Send-RjRbReportEmail](/pt/dev-reference/report-functions/send-rjrbreportemail.md) — utilitário complementar para entregar relatórios por email; normalmente combinado com esta função para manter pequena a carga útil do email.
* Documentação Microsoft: [Autorizar com Shared Key](https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key) — esquema de assinatura usado pelo auxiliar.
* Documentação Microsoft: [Criar um SAS de serviço](https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas) — formato do token SAS devolvido em `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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

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

The question should be specific, self-contained, and written in natural language.
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.
