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

# Publish-RjRbFilesToStorageContainer

## 概要

`Publish-RjRbFilesToStorageContainer` は、RealmJoin のレポート実行用 runbook から Azure Blob Storage 経由でレポートファイル（CSV、XLSX、ZIP、…）を配信するための標準ヘルパーです。1 つ以上のローカルファイルを対象コンテナーへアップロードし、各 blob に対して期限付きの SAS ダウンロードリンクを返します。これはレポートメール、Teams メッセージ、または runbook の出力に含めるのに適しています。

主な特性:

* **なし `Az.Storage` 依存関係** — blob 操作は Azure Storage REST API に直接対して実行されます（コンテナー作成、アップロード、SAS token 生成）。これにより、以下の間で起こるよく知られたアセンブリ競合が解消されます。 `Az.Storage` と `ExchangeOnlineManagement` は、混在したレポート runbook で表面化します。
* **自動接続** — もし `Az` のコンテキストが有効でなければ、関数は透過的に `Connect-RjRbAzAccount`を呼び出します。任意の `-SubscriptionId` により、いずれかのストレージ操作の前にコンテキストを切り替えます。
* **コンテナーの自動作成** — 対象コンテナーがまだ存在しない場合は、その場で作成されます。既存のコンテナー（HTTP 409）は成功として扱われます。
* **HttpClient ベースのアップロード** — `System.Net.Http.HttpClient` を直接使用します。これは Azure Automation の `Invoke-RestMethod` インターセプターが、バイナリ本文に対して必要なカスタムヘッダー（`x-ms-blob-type`）を削除してしまうためです。
* **読み取り専用 SAS リンク** — 返される各 URL はストレージ アカウント キーで署名され、単一 blob にスコープされ、HTTPS のみで有効、かつ `LinkExpiryDays` 日間（既定 6）有効です。

通常の runbook が使用する中心的なストレージ設定（リソース グループ、アカウント名、有効期限日数、blob 名プレフィックス）は RealmJoin のカスタマイズ JSON にあり、 [Runbook Report Settings — Storage Account Delivery](/ja/zi-dong-hua/runbooks/runbook-report-settings.md#storage-account-delivery)で文書化されています。このドキュメントでは、runbook からこの関数を呼び出す方法に焦点を当てます。

## 前提条件

### Azure Storage Account

既存の Azure Storage Account（一般用途 v2 推奨）が必要です。対象コンテナーは事前に存在している必要はありません — 初回使用時に自動的に作成されます。

### ストレージ アカウント上の Azure RBAC

Automation Account のマネージド ID（または runbook で使用する service principal）には、ストレージ アカウントまたはそのリソース グループに対して次の権限が必要です:

| 操作                                                  | 必要用途                                 |
| --------------------------------------------------- | ------------------------------------ |
| `Microsoft.Storage/storageAccounts/read`            | ストレージ アカウントの読み取り                     |
| `Microsoft.Storage/storageAccounts/listKeys/action` | SharedKey 署名と SAS 生成に使用するアカウント キーの取得 |

組み込みロールの **Storage Account Contributor** は両方をカバーします。 **Storage Blob Data Contributor** だけでは *不十分* です。というのも、この関数は AAD による blob 操作ではなくアカウント キーで要求を署名するためです。

### モジュール接続性

この関数には runbook 環境で `Az.Accounts` モジュールが必要です（`Get-AzContext`, `Set-AzContext`, `Connect-AzAccount`, `Invoke-AzRestMethod`）。呼び出し側の runbook で明示的に宣言してください:

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

もし `Az.Accounts` が実行時に利用できない場合、関数は明確なエラーメッセージとともに即座に失敗します — 事前に `Get-AzContext` をチェックし、 *"Publish-RjRbFilesToStorageContainer requires the 'Az.Accounts' module. Add #Requires -Modules @{ModuleName = 'Az.Accounts'; ModuleVersion = '5.3.4'} to the calling runbook."* を、いかなる Azure 呼び出しより前に投げます。

> **なぜ `Az.Accounts` が `RequiredModules` エントリとして `RealmJoin.RunbookHelper.psd1`?**
>
> `Az.Accounts` に宣言されず、 `ExternalModuleDependencies` の下にのみ（情報用として） *不十分* および `RequiredModules` の下に（Import-Module `時に強制）` として列挙されているのですか:
>
> * **使った分だけ支払う。** 多くの runbook は Graph ベースのヘルパーのみを使用します（例: `Send-RjRbReportEmail` を `-UseNativeGraphRequest`なしで、または `Invoke-RjRbRestMethodGraph`）し、Az.\* の cmdlet には一切触れません。 `Az.Accounts` を `RequiredModules` に昇格させると、コードパス上で必要なくても、すべての呼び出し側 runbook がそのモジュールを同梱する必要が生じます。これは Azure Automation におけるコールドスタート時間を測定可能なほど増加させます。
> * **バージョンの衝突を避ける。** 厳密な `RequiredModules` 制約は import 時に自動解決を引き起こし、runbook 自身が固定している特定の `Az.Accounts` バージョンを引き込んでしまう可能性があります（Az.\* のサブモジュールは非常にバージョン依存です）。runbook に自身の `#Requires -Modules` を宣言させることで、バージョン選択を呼び出し側に残せます。
> * **runbook ごとの権限。** Azure Automation では、モジュール要件を宣言する標準的な場所は helper module レベルではなく runbook レベルの `#Requires`です。helper module は依存関係を情報として（マニフェスト内の `ExternalModuleDependencies` 経由で）および上記の実行時チェックで公開し、設定ミスは静かにバージョン競合を覆い隠すのではなく、実行可能なメッセージ付きで明確に失敗します。

`Az.Storage` は **不十分** 必須であり、上述のアセンブリ競合を避けるため同じ runbook に import してはなりません。

## クイック スタート

最小限の呼び出しには、ローカルファイルのパス、コンテナー名、リソース グループ名、ストレージ アカウント名が必要です:

```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
```

これにより `devices.csv` を `reports` コンテナーの `stcontosoreports` へアップロードし、blob 名、SAS 有効期限タイムスタンプ、そして既定の 6 日間有効な共有用ダウンロード URL を含む 1 つのオブジェクトを返します。

## パラメーター

### 必須

| パラメーター               | 型          | 説明                                                                                                                                         |
| -------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `FilePaths`          | `string[]` | アップロードする 1 つ以上のローカルファイル パス。各パスは既存ファイル（`Test-Path -PathType Leaf`）を指していなければならず、いずれかが見つからない場合は関数が事前に例外を投げます。                                 |
| `ContainerName`      | `string`   | 対象 blob コンテナー。存在しない場合は自動的に作成されます。Azure のコンテナー命名規則（小文字、3～63 文字、英数字 + ハイフン）に従う必要があります。コンテナー名は *runbook ごとの* 判断であり、中央設定ではなく runbook 内で設定されます。 |
| `ResourceGroupName`  | `string`   | ストレージ アカウントを含むリソース グループ。通常は中心設定 `RJReport.AzureStorage.ResourceGroup`.                                                                     |
| `StorageAccountName` | `string`   | Azure Storage Account の名前。通常は中心設定 `RJReport.AzureStorage.StorageAccountName`.                                                              |

### 任意

| パラメーター              | 型        | 既定        | 説明                                                                                                                               |
| ------------------- | -------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `SubscriptionId`    | `string` | 現在のコンテキスト | ストレージ アカウントをホストする Azure サブスクリプション。指定した場合、 `Set-AzContext -Subscription` が、いずれかのストレージ操作の前に呼び出されます。指定しない場合は現在の `Az` コンテキストを使用します。  |
| `LinkExpiryDays`    | `int`    | `6`       | SAS リンクの有効期間（日数）。 `[1, 3650]`まで有効と検証されます。単一呼び出し内のすべての blob に同じ有効期限タイムスタンプが適用されます。通常は中心設定 `RJReport.AzureStorage.LinkExpiryDays`. |
| `AddBlobNamePrefix` | `bool`   | `$false`  | ときに `$true`なら、blob 名には `yyyyMMdd-HHmmss-` が前置されます（アップロード時の `Get-Date` のタイムスタンプ）。これにより、繰り返し実行時の上書きを防ぎます。元のファイル名は接尾辞として保持されます。     |

> **注:** これらのパラメーターと中心的な RealmJoin のカスタマイズ JSON との対応（推奨既定値を含む）は [Runbook Report Settings — Storage Account Delivery](/ja/zi-dong-hua/runbooks/runbook-report-settings.md#storage-account-delivery).

## 使用例

### 推奨 runbook パターン

これはレポート runbook で使用される標準パターンです。ストレージ設定は `Use-RJInterface -Type Setting`を介して中心の RealmJoin カスタマイズから取得され、コンテナーは runbook ごとにハードコードされ、設定が欠けている場合は runbook は実行可能なメッセージとともに中止されます:

```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)) {
    "## ストレージ アカウントへエクスポートするには、RJ Runbooks Customization を使用してください"
    "## ( https://portal.realmjoin.com/settings/runbooks-customizations ) を使って次を設定してください:"
    "##   - RJReport.AzureStorage.ResourceGroup"
    "##   - RJReport.AzureStorage.StorageAccountName"
    throw "ストレージ アカウント設定がありません。"
}

# … エクスポート ファイルを生成する …
$exportPath = "myReport.csv"

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

$uploadResult = $uploadResults[0]
"## エクスポートが作成されました。"
"## リンクの有効期限: $($uploadResult.EndTime)"
$uploadResult.SASLink | Out-String
```

このパターンを採用する際に守っておくとよい慣例がいくつかあります:

* 3 つの中心設定（`ResourceGroup`, `StorageAccountName`, `LinkExpiryDays`）は `Use-RJInterface -Type Setting`を介して配線された runbook パラメーターとして公開されますが、通常は *非表示* にして runbook customization（`"Hide": true`）に入れ、エンドユーザーには見えないようにします。
* コンテナー名は runbook ごとにハードコードされ（多くの場合、 `param` の既定値経由で）、ライフサイクル ポリシーとアクセス制御をエクスポート種別ごとに調整できるようにします — これは意図的に *不十分* 中心設定ではありません。
* `AddBlobNamePrefix $true` は、毎回同じファイル名を生成する定期エクスポートの安全な既定値です。
* この関数は、runbook のメイン `try { … } catch { throw $_ } finally { Disconnect-AzAccount … }` ブロック内で呼び出されるため、部分的な失敗は Automation ジョブへ伝播し、成功時であっても Az コンテキストは解放されます。

### 1 回の呼び出しで複数ファイル

`FilePaths` 配列を受け入れます。各ファイルは順番にアップロードされ、アップロードされた各 blob ごとに結果オブジェクトが返されます。

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

foreach ($r in $results) {
    "Uploaded $($r.BlobName) — download until $($r.EndTime): $($r.SASLink)"
}
```

### カスタムなリンク有効期間と明示的なサブスクリプション

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

runbook が複数のサブスクリプションにまたがる場合や、下流の受信者が既定の 6 日より長い期間を必要とする場合に便利です。

### と組み合わせる `Send-RjRbReportEmail`

よくあるパターンは、大きなデータを blob storage にアップロードし、SAS リンクをレポートメールに埋め込み、メールを Graph の 4 MB `sendMail` 制限より十分小さく保つことです:

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

$linkLine = "[Download {0}]({1}) (valid until {2:yyyy-MM-dd HH:mm} UTC)" -f `
    $uploaded[0].BlobName, $uploaded[0].SASLink, $uploaded[0].EndTime.ToUniversalTime()

$reportMd = @"
# デバイス インベントリ

完全なデバイス一覧はダウンロードとして利用できます:

$linkLine
"@

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

こちらを参照 [Send-RjRbReportEmail](/ja/dev-reference/report-functions/send-rjrbreportemail.md) このパターンのメール側について。

## 動作とエラー処理

### 事前のファイル検証

いかなる Azure 呼び出しの前にも、関数は `FilePaths` を走査し、 `File '<path>' was not found.` を最初に見つからない項目に対して投げます。これにより、呼び出し側が টাইポを渡した場合の部分アップロードを防ぎます。

### Azure コンテキストの解決

`Get-AzContext` が最初にチェックされます。コンテキストがない、またはコンテキストに `Account` （例: 新しい runbook 実行）のいずれも含まれない場合、関数はマネージド ID を認証するために `Connect-RjRbAzAccount` を呼び出します。 `-SubscriptionId` が指定された場合、 `Set-AzContext -Subscription` が次に呼び出されます。

### コンテナー作成

コンテナーは次の `PUT …?restype=container` 要求で作成されます:

* **HTTP 201** — コンテナーが作成されました。
* **HTTP 409** — コンテナーは既に存在します。成功として扱われます。
* **その他のステータス** — 関数は `Container creation failed (<status>): <body>`.

### アップロード失敗

各ファイルは `HttpClient.SendAsync`を介してアップロードされます。成功でないステータスは `Blob upload failed (<status>): <body>`で呼び出しを終了します。これには Azure Storage から返された生のエラーが含まれます。同じ呼び出し内ですでにアップロード済みの先行ファイルはストレージ アカウント上に残ります — 部分アップロードが許容できない場合は、呼び出し側で try/catch で囲み、クリーンアップを行うとよいでしょう。

### キー取得失敗

`Invoke-AzRestMethod` は ARM の `listKeys` エンドポイントを呼び出すために使用されます。応答ステータスが 200 以外であれば、関数は `Failed to retrieve storage account keys for '<account>' in resource group '<rg>'. Status: <status>`を投げます。最も一般的な原因は次のとおりです:

* 欠如 `Microsoft.Storage/storageAccounts/listKeys/action` がマネージド ID に対してあること。
* サブスクリプション コンテキストの誤り（ `-SubscriptionId`).
* の টাইपो `StorageAccountName` または `ResourceGroupName`.
* 中心設定が `RJReport.AzureStorage.ResourceGroup` / `RJReport.AzureStorage.StorageAccountName` 未構成 — [Runbook Report Settings](/ja/zi-dong-hua/runbooks/runbook-report-settings.md#storage-account-delivery).

### SAS token の特性

生成される token には次が使われます:

* `sv=2023-11-03` （署名バージョン）
* `sr=b` （blob スコープ）
* `sp=r` (読み取り専用)
* `spr=https` (HTTPS のみ)
* `st` 5分前に設定し（クロックスキューの許容）、および `se` を `LinkExpiryDays` 呼び出し時点から。

トークンはストレージ アカウントのキーで署名されます。 **リンクを持つ人は、期限まで BLOB をダウンロードできます** — 返された SAS URL は秘密情報として扱ってください。

## 出力

各アップロードが成功すると、 `PSCustomObject` 次のプロパティを持ちます:

| プロパティ      | 型          | 説明                                                                       |
| ---------- | ---------- | ------------------------------------------------------------------------ |
| `BlobName` | `string`   | コンテナー内の最終的な BLOB 名。必要に応じてタイムスタンプ接頭辞も含まれます `AddBlobNamePrefix` は `$true`. |
| `EndTime`  | `datetime` | ローカル時刻の SAS の有効期限（URL には UTC としてもエンコードされます）。                             |
| `SASLink`  | `string`   | 埋め込み SAS トークンを含む、完全修飾 HTTPS ダウンロード URL。                                  |

結果は同じ順序で返されます `FilePaths`。単一ファイルをアップロードする場合でも戻り値は配列です — そのため`$results[0]`でインデックス指定するか `foreach` を使って反復処理し、スカラーとして扱わないでください。

## 関連項目

* [Runbook Report Settings — Storage Account Delivery](/ja/zi-dong-hua/runbooks/runbook-report-settings.md#storage-account-delivery) — レポート用ランブックで使われる、ストレージ アカウント、リンクの有効期限、BLOB 名プレフィックスの中央設定。
* [Send-RjRbReportEmail](/ja/dev-reference/report-functions/send-rjrbreportemail.md) — メールでレポートを配信するための補助ヘルパー。メールのペイロードを小さく保つため、この関数とよく組み合わせて使われます。
* Microsoft Docs: [Shared Key を使用して承認する](https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key) — このヘルパーで使用される署名方式。
* Microsoft Docs: [サービス SAS を作成する](https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas) — 返される SAS トークンの形式 `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/ja/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.
