dataflows-authoring-cli について
Microsoft Fabric Dataflows Gen2をコマンドラインで作成・編集するスキルです。要件を確認したうえで、プレビューや検証、任意の更新までを支援します。
主な機能
- 01データフローの一貫した作成
- 02既存データフローの編集
- 03候補 M クエリのプレビュー
- 04出力先の管理
- 05定義とバインドの検証
- 06任意でデータフローを更新
活用シーン
- 01指定したソースと変換で Dataflow を作成
- 02既存データフローの定義を更新
- 03変更を保存する前にクエリ結果を確認
- 04クエリ結果を対応する出力先に書き込む
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ microsoft/ skills-for-fabric --skill dataflows-authoring-cliインストール後、Claude Code で/dataflows-authoring-cliを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/authoring-cli-quickref.mdauthoring-script-templates.mdconnection-management.mdconnectors.mdm-language.mdmashup-preview.mdoutput-destinations.mdreferences/charts/bar_chart.pyline_chart.py詳細
更新チェック — セッションごとに1回(必須) このスキルをセッションで初めて使用するときは、作業を進める前に check-updates スキルを実行してください。
- GitHub Copilot CLI / VS Code:
check-updatesスキルを呼び出します。- Claude Code / Cowork / Cursor / Windsurf / Codex:ローカルとリモートの package.json のバージョンを比較します。
- このセッション中にすでにチェックを実行している場合はスキップしてください。
重要な注意事項
- ワークスペース名からワークスペースの詳細(IDを含む)を取得するには、すべてのワークスペースを一覧表示してから、JMESPath でフィルタリングします。
- ワークスペース ID、項目の種類、項目名から項目の詳細(IDを含む)を取得するには、そのワークスペース内の該当する種類の項目をすべて一覧表示してから、JMESPath でフィルタリングします。
変更前の要件確認ゲート(必須) 変更を行う前に、依頼された操作に対するユーザーの意図が十分に確認できていることを確かめてください。 作成または更新の依頼では、ソース、クエリ/スキーマと変換、出力先の動作、更新動作を確認します(出力先なし、または更新なしを明示的に選択する場合も含みます)。「レポート作成に必要な Dataflow を設定して」のような一般的な依頼の場合は、必要事項を確認する質問を構造化して行い、変更を行う前に停止してください。無関係なワークスペース項目から要件を推測したり、推測に基づいてソース、接続、Dataflow を作成したりしないでください。
dataflows-authoring-cli — CLI による Dataflows Gen2 の作成
目次
このスキル(SKILL.md)
| セクション | 内容 |
|---|---|
| ツールスタック | az + jq + base64 + curl |
| 接続 | ワークスペース/データフロー ID の特定 |
| エージェント型ワークフロー | まずここから。 A:エンドツーエンドで作成、B:既存のものを変更、C:プレビューのループ |
| 必須事項/回避事項/推奨事項 | 作成ルール |
| トラブルシューティング | 症状 → 対処方法の表 |
| 例 | 実行可能な bash + PowerShell のレシピ |
| 出力に関する期待事項 | 応答の規約 |
リファレンス(references/ 内)
| ファイル | 参照するタイミング |
|---|---|
| authoring-cli-quickref.md | 1 行のレシピ、ステータス列挙型、base64 ヘルパー、接続バインドの簡易パターン |
| authoring-script-templates.md | bash + PowerShell の完全なテンプレート、エンドツーエンドのスモークテスト、LRO ポーリングパターン |
| connection-management.md | 接続の一覧表示/作成/調査、supportedConnectionTypes、ClusterId の解決、ID 形式のチートシート |
| connectors.md | M 側のソースコネクタ:ライブ検証済み関数の一覧、Lakehouse の詳細なナビゲーション、Web.Page / Web.BrowserContents のゲートウェイ範囲、Html.Table / Csv.Document / Json.Document のパターン |
| m-language.md | Dataflow Gen2 の M 言語セマンティクス:try のレコード形式、列変換におけるセル単位のエラーラップ、行とサブテーブルのコンテキストにおける each のスコープ、オプションのフィールドアクセス [?] / Record.FieldOrDefault、引用符付き識別子、サンドボックスで無効化されているシンボル(File.Contents) |
| mashup-preview.md | executeQuery の契約:ブートストラップ分岐、自動ラップルール、範囲のないプレビューを絶対に避けること |
| output-destinations.md | 出力先のパターン:Lakehouse Table、Lakehouse Files、Warehouse、ADX、Azure SQL。DataDestinations 注釈、非表示のクエリ、loadEnabled のルール、接続の制限 |
共通リファレンス(../../common/ 内)
| ファイル | 参照するタイミング |
|---|---|
| COMMON-CLI.md | az login、トークンの取得、az rest、ページネーション、LRO ポーリング、CLI の注意点。§ Fabric のワークスペースとアイテムの検索は必須です。 |
| COMMON-CORE.md | Fabric のトポロジ、環境 URL、認証、コア REST API の範囲 |
| ITEM-DEFINITIONS-CORE.md | 定義エンベロープ、アイテム種別ごとのペイロード契約 |
| DATAFLOWS-AUTHORING-CORE.md | 作成機能のマトリックス、3 部構成の定義、M の構造、接続モデル、ALM/Git の統合 |
関連スキル
| スキル | 用途 |
|---|---|
| dataflows-consumption-cli | 永続化されたクエリの実行、永続化を意図しないアドホックな読み取り専用の customMashupDocument、Arrow → CSV/pandas 変換、更新の状態/履歴。 |
ツールスタック
| ツール | 役割 | インストール |
|---|---|---|
az CLI | 主要ツール:認証(az login)、REST API 呼び出し(az rest)、トークンの取得。 | ほとんどの開発環境にプリインストールされています |
jq | JSON レスポンスと定義ペイロードの解析および操作。 | プリインストール済み、または簡単にインストールできます |
base64 | REST API 用の定義パーツのエンコード/デコード。 | bash に組み込み済み/PowerShell の [Convert]::ToBase64String() |
curl | 生の HTTP を制御する必要がある場合の az rest の代替手段。 | プリインストール済み |
uuidgen | 新しいデータフロー定義の作成時(ワークフロー A)に、queryId と logicalId 用のクエリごと/プラットフォームごとの GUID を生成します。 | Linux/macOS ではプリインストール済み。Windows では PowerShell の [guid]::NewGuid().Guid を使用するか、WSL 経由で実行してください |
エージェントの確認事項 — 初回操作の前に、
az、jq、curlが使用可能であることを確認してください。uuidgenが必要なのはワークフロー A(作成)のみです。 インストールと認証の設定については、COMMON-CLI.md を参照してください。
接続
ワークスペース ID とデータフロー ID の確認
COMMON-CLI.md の Fabric のワークスペースとアイテムの検索に従ってください。
# List workspaces — find workspace ID by name
az rest --method get \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces" \
--query "value[?displayName=='MyWorkspace'].id" --output tsv
# List dataflows in workspace — find dataflow ID by name
WS_ID="<workspaceId>"
az rest --method get \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/dataflows" \
--query "value[?displayName=='MyDataflow'].id" --output tsv
再利用可能な接続変数
WS_ID="<workspaceId>"
DF_ID="<dataflowId>"
API="https://api.fabric.microsoft.com/v1"
RESOURCE="https://api.fabric.microsoft.com"
エージェントワークフロー
一般的な作成タスクを対象とする、3 つのワークフローがあります。
- A. 新しいデータフローを最初から最後まで作成する — 接続を検索/作成し、データフローを作成して、M とバインディングを保存し、検証して、必要に応じて更新します。
- B. 既存のデータフローを変更する — 定義の読み取り、変更、書き込みを行います。標準的な「検索 → 作成 → 実行 → 検証」のループです。
- C. プレビューを活用した作成ループ —
updateDefinitionで保存する前に、executeQueryを使って候補となる M を反復処理します。 - D. 出力先 —
DataDestinationsアノテーションを介して、クエリ結果を Lakehouse(テーブル/ファイル)、Warehouse、ADX、または Azure SQL に書き込みます。リファレンス全体は output-destinations.md を参照してください。
A. 新しいデータフローを最初から最後まで作成する
データフローがまだ存在しない場合に使用します。接続の検索または作成、データフローのシェルの作成、1 回の updateDefinition での M とバインディングの保存、検証、必要に応じた更新まで、成功までの一連の手順を扱います。
手順:
- 既存の接続を一覧表示し、
connectionDetails.typeと対象の URL/ホストで絞り込みます。一致するものがあれば再利用します(GET /v1/connections+ JMESPath)。 - 一致するものがなければ、接続を作成します。 まず
GET /v1/connections/supportedConnectionTypesを実行して、必須パラメーターとサポートされている資格情報の種類を確認し、次にPOST /v1/connectionsを実行します(同期 201)。リクエスト本文の形式と資格情報スキーマについては、connection-management.md を参照してください。 - 複合バインディング用の
ClusterIdを解決します。GET https://api.powerbi.com/v2.0/myorg/me/gatewayClusterDatasourcesを--query "value[?id=='$CONN_ID'] | [0].clusterId"とともに実行します。audience は--resource "https://analysis.windows.net/powerbi/api"です(末尾のスラッシュは付けません)。ID ごとのルートは、クラウド接続に対してPowerBIEntityNotFoundを返します。新しく作成した接続が反映されるまで数秒かかることがあるため、空の場合は再試行してください。詳細は、connection-management.md § ClusterId の解決 を参照してください。 - データフローのシェルを作成します。
POST /v1/workspaces/{ws}/dataflowsに{"displayName":"<displayName>"}を指定すると、同期 201 が返ります。作成時にdefinitionフィールドを指定する必要はなく、次の手順で設定できます。代わりに、この作成 POST で完全なdefinition(3 つの部分すべて)を指定する場合は、この呼び出しが永続化の手段になります。概要では、永続化のパスとしてupdateDefinitionではなくPOST /v1/workspaces/{ws}/dataflowsと記載してください。 - M と接続バインディングを 1 回の呼び出しで保存します。 3 つの部分を指定して
POST /v1/workspaces/{ws}/dataflows/{df}/updateDefinition?updateMetadata=trueを実行します。mashup.pq(実際のWeb.Contents/Sql.Database/…)、queryMetadata.json(connections[]を設定し、各connectionIdに{"ClusterId":"…","DatasourceId":"…"}を文字列化した値を指定)、および.platformです。通常は同期 200 が返ります。大きな本文では 202 と LRO のLocationが返る場合があるため、どちらにも対応してください。 - バインディングが永続化されたことを確認します。
getDefinitionを再度呼び出し、queryMetadata.jsonをデコードして、connections[]がそのまま保持されていることを確認します。確認にはGET /items/{id}/connectionsを使用しないでください。このエンドポイントが反映するのは永続化された定義ではなく、更新によって具体化された状態であり、バインドが成功していても 0 を返します。AVOID を参照してください。 条件付きのプレビュー専用フォールバック: Power BI v2 のgatewayClusterDatasourcesが 401/403/Unauthorized を返す、または再試行してもClusterIdが確認できないために接続バインディングを進められない場合でも、データフローの作成前に処理を止めないでください。シェルを作成し、有効なソースバインディングが設定済みだと主張せずに、保存済みのクエリ定義を永続化します。保存済みの各クエリについてQueryNameのみを指定してexecuteQueryを呼び出し、Arrow ストリームから正確な資格情報エラーまたはバインディングエラーを提示してください。グラフのデータを捏造せず、更新もしないでください。 - (推奨)出力を ASCII グラフでプレビューするか、ユーザーに確認します。 ユーザーに 「最初の更新の前に、データをグラフでプレビューしますか?」 と尋ねてください。この作成フローでは手順 5 ですでに定義が保存されているため、ここでのグラフプレビューは 更新によって具体化する前に行う、保存後の検証ゲート であり、保存前の手順ではありません。(最初の
updateDefinitionの前に候補の M を検証する場合(たとえば M を調整する場合や、資格情報が設定されたソースをブートストラップバインドしてexecuteQueryから参照できるようにする場合)は、保存前の プレビュー主導の作成ループ を使用してください。グラフの描画方法は同じで、保存との順序だけが異なります。)承諾された場合は各エンティティに対してexecuteQueryを呼び出し、Arrow IPC ストリームを解析して、references/charts/line_chart.py/references/charts/bar_chart.pyを使って折れ線グラフ(時系列)または横棒グラフ(カテゴリ)を描画し、続行前にユーザーに確認してください。詳細は、mashup-preview.md § ASCII グラフプレビュー を参照してください。辞退された場合は、手順 8 に直接進んでください。 - (任意)更新を開始してデータを具体化します。本文に
{"executionData":{"executeOption":"ApplyChangesIfNeeded"}}を指定してPOST .../jobs/instances?jobType=Refreshを実行します。定義を変更した後の最初の更新では、ApplyChangesIfNeededが必須です。 指定しないと、Fabric は以前に適用された定義を更新します。LRO をポーリングし、statusがCompleted(更新の列挙値)、またはFailed/Cancelledになるまで待ちます。
# Concise skeleton — full runnable bash is Example 1 below.
# PowerShell + LRO-polled variants: references/authoring-script-templates.md
WS_ID="<workspaceId>"; URL="<source-url>"
RES="https://api.fabric.microsoft.com"; API="$RES/v1"
PBI="https://analysis.windows.net/powerbi/api"
# 1. List existing & try reuse
CONN_ID=$(az rest --method get --resource "$RES" --url "$API/connections" \
--query "value[?connectionDetails.type=='Web' && connectionDetails.path=='$URL'] | [0].id" -o tsv)
# 2. Create connection if missing — see connection-management.md for full body
# 3. List+filter for ClusterId
CLUSTER_ID=$(az rest --method get --resource "$PBI" \
--url "https://api.powerbi.com/v2.0/myorg/me/gatewayClusterDatasources" \
--query "value[?id=='$CONN_ID'] | [0].clusterId" -o tsv)
# 4. Empty dataflow shell — sync 201
SHELL_BODY=$(mktemp --suffix=.json 2>/dev/null || mktemp)
printf '{"displayName":"my-df"}' > "$SHELL_BODY"
DF_ID=$(az rest --method post --resource "$RES" \
--url "$API/workspaces/$WS_ID/dataflows" \
--headers "Content-Type=application/json" \
--body "@$SHELL_BODY" --query id -o tsv)
rm -f "$SHELL_BODY"
# 5. One-shot updateDefinition with real M + connections[] (sync 200 typical)
# Body assembly (mashup.pq + queryMetadata.json + .platform, base64-encoded;
# queryMetadata.json.connections[].connectionId = composite ClusterId/DatasourceId):
# see Example 1 below.
# 6. Verify via getDefinition (NOT GET /items/{id}/connections — see AVOID)
# 7. (optional) executeQuery — Workflow C
# 8. (optional) Refresh with executeOption=ApplyChangesIfNeeded — Example 2
一括処理と、バインド+保存の2段階処理。 ステップ4〜5は、1回の呼び出しで実行することも(デフォルト。HTTPの往復を1回分節約できます)、ブートストラップ用のバインドを行う
updateDefinitionに続けて、完全なMを指定したupdateDefinitionを実行する2段階に分けることもできます。どちらも有効です。PREFERを参照してください。
B. 既存のデータフローを変更する
データフローがすでに存在する場合に使用します。Discover → Formulate → Execute → Verifyの標準的なループです。データフローがまだ存在しない場合は、代わりにワークフローAを参照してください。
- Discover — ワークスペースとデータフローを一覧表示し、
getDefinitionを実行します(mashup.pqとqueryMetadata.jsonをデコード)。GET /v1/connections/{id}を使って、すべてのconnections[]エントリを検証します。 - Formulate — Mを変更し、各パーツを再エンコードして、参照されているすべての
connectionIdが呼び出し元の接続ストアに存在することを確認します。 - Execute — 3つのパーツすべてを指定して
POST .../updateDefinition?updateMetadata=trueを実行します(完全置換)。必要に応じて更新をトリガーします。 - Verify —
getDefinitionを再度呼び出して変更を確認し、更新のLROをポーリングします。更新に失敗した場合は、修正可能なM/ソースの問題を特定するためのexecuteQueryによる切り分けを最大1回試みます。終端的な失敗、または再試行不可能な失敗(isRetriable: false、ワークスペース全体に及ぶUnknownException)の場合は、生のエラーを提示し、再トリガーせずに停止します。
# Concise skeleton — full templates: references/authoring-script-templates.md
# Acquire $TOKEN per common/COMMON-CLI.md § Token-in-Variable Pattern (resource = $RESOURCE).
RESOURCE="https://api.fabric.microsoft.com"; API="$RESOURCE/v1"
# 1. Discover — getDefinition (handles 200 sync and 202 + LRO via curl)
HDR=$(mktemp); BODY=$(mktemp)
CODE=$(curl -sS -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Length: 0" \
"$API/workspaces/$WS_ID/dataflows/$DF_ID/getDefinition" \
-D "$HDR" -o "$BODY" -w "%{http_code}")
if [ "$CODE" = "202" ]; then
LOC=$(tr -d '\r' < "$HDR" | grep -i "^location:" | awk '{print $2}')
RETRY=$(tr -d '\r' < "$HDR" | grep -i "^retry-after:" | awk '{print $2}'); RETRY=${RETRY:-5}
while :; do
sleep "$RETRY"
OP=$(az rest --method get --resource "$RESOURCE" --url "$LOC")
case "$(echo "$OP" | jq -r '.status // empty')" in
Succeeded) RESULT=$(az rest --method get --resource "$RESOURCE" --url "${LOC%/}/result"); break ;;
Failed|Cancelled) echo "ERROR: getDefinition $(echo "$OP" | jq -r '.status')" >&2; exit 1 ;;
esac
done
else
RESULT=$(cat "$BODY")
fi
rm -f "$HDR" "$BODY"
# Validate bound connections (connectionId is a composite JSON string — iterate safely)
QUERY_META=$(echo "$RESULT" | jq -r '.definition.parts[] | select(.path=="queryMetadata.json") | .payload' | base64 -d)
echo "$QUERY_META" | jq -c '.connections[]?' | while IFS= read -r conn; do
RAW=$(echo "$conn" | jq -r '.connectionId')
DATASOURCE_ID=$(echo "$RAW" | jq -r '.DatasourceId? // empty' 2>/dev/null)
[ -z "$DATASOURCE_ID" ] && DATASOURCE_ID="$RAW"
# GET /v1/connections/$DATASOURCE_ID to confirm access
done
# 2-3. Formulate & Execute — see Example 3
# 4. Verify — trigger refresh via curl (az rest cannot capture Location header).
# Full LRO polling: references/authoring-script-templates.md.
C. プレビュー主導の作成ループ(保存前のexecuteQuery — mashup-preview.mdを参照)
変更がPower Query M(新しいクエリ、編集したマッシュアップ、新しいソース、変更したパラメーター)に関わる場合は、保存する前に、候補のcustomMashupDocumentをデータフローのバインド済み接続に対してプレビューします。作成時に構文、スキーマ、資格情報のエラーを検出できます。順序に沿った全ステップ、ブートストラップ分岐、自動ラップのルール、無制限のプレビューを避けるための強い注意、ASCIIチャートのプレビュー、Apache Arrowの処理については、mashup-preview.md § プレビュー主導の作成ループを参照してください。
意図の使い分け。 このワークフローは、保存前の操作を対象としています。保存済みのクエリ(
QueryNameのみ)を実行する場合、または保存する意図のないアドホックな読み取り専用のcustomMashupDocumentを実行する場合は、dataflows-consumption-cliを使用してください。mashup-preview.mdは、どちらの操作にも共通するAPIリファレンスです。
メタデータのみの編集(表示名、スケジュール、loadEnabledの切り替え)の場合、またはエージェントが明確なスキップ理由(ブートストラップ、コストが過大、ソースに副作用がある)を記録する場合に限り、プレビューを省略してください。
D. 出力先
データフローでクエリ結果を外部ストア(Lakehouse テーブル、Lakehouse ファイル、Warehouse、ADX、Azure SQL)に書き込む場合に使用します。DataDestinations アノテーションと非表示の出力先クエリを追加して、ワークフロー A を拡張します。完全な例を含むリファレンスは、output-destinations.md を参照してください。
主な要件:
- ソースクエリには、出力先クエリを名前で参照する
[DataDestinations = {[...]}]アノテーションを含めます。 - 非表示の出力先クエリ(末尾に
_DataDestinationを付けます)では、null 安全な?[Data]?(テーブル)または?[Content]?(ファイル)演算子を使って、対象のストレージに移動します。 - queryMetadata.json では、出力先クエリの
"loadEnabled": falseを設定する必要があります。設定しないと更新に失敗します。概要には、パーツ名をそのまま使って記載してください(例:「queryMetadata.jsonの出力先クエリでloadEnabled: falseを設定」)。 - API で作成したデータフローでは、既存のテーブルであっても、常に
IsNewTarget = trueを使用してください。 - 適切な接続をバインドします(Lakehouse:kind
"Lakehouse"、Warehouse:kind"Warehouse"、ADX:kind"AzureDataExplorer"、Azure SQL:kind"Sql")。ID にはClusterIdとDatasourceIdの複合値を使用します。 - 初回の更新では、必ず
ApplyChangesIfNeededを使用してドラフトを公開し、アノテーションを調整します。 - すべてのソース列に型を指定します。
Any型の列は、すべての出力先タイプで拒否されます。 - 記述する概要には、定義パーツ名を含めてください。 CLI のトランスクリプトでは長いコマンド本体が省略されるため、最終的な概要(シェルコマンドだけでなく、文章で記述した概要)には、3 つの定義パーツをそのままのパスで記載する必要があります。これにより、回答内にパーツ名が残ります(例:「
updateDefinitionでmashup.pq+queryMetadata.json+.platformを保存」)。queryMetadata.jsonを「クエリメタデータ」と略したり、内部フィールドのqueriesMetadataを使ったりしないでください。
対応している出力先:
| 出力先 | 接続の種類 | 出力先クエリ関数 | 備考 |
|---|---|---|---|
| Lakehouse テーブル | Lakehouse | Lakehouse.Contents(...) | パス:「Lakehouse」 |
| Lakehouse ファイル | Lakehouse | Lakehouse.Contents(...) | TypeSettings = [Kind = "File"]、?[Content]? |
| Warehouse | Warehouse | Fabric.Warehouse(...) | パス:「Warehouse」、スキーマ/項目のナビゲーション |
| Azure Data Explorer | AzureDataExplorer | AzureDataExplorer.Contents(...) | パスは接続と完全に一致させる必要があります(末尾のスラッシュも含む!) |
| Azure SQL | Sql | Sql.Database(...) | パス:「server;database」 |
最小限の手順: データフローを作成 → 接続を検索/作成 → ClusterId を解決 → OD アノテーションを含む定義を保存 → 確認 → 更新。
# Skeleton — full PowerShell recipe: references/output-destinations.md § Complete Example
WS_ID="<workspaceId>"; LH_ID="<lakehouseId>"; RES="https://api.fabric.microsoft.com"
# M pattern (two queries):
# 1. Source with [DataDestinations] annotation
# 2. Hidden _DataDestination query with ?[Data]? null-safe navigation
# queryMetadata: source loadEnabled=true, destination loadEnabled=false + isHidden=true
# Refresh: {"executionData":{"executeOption":"ApplyChangesIfNeeded"}}
注意点、ルール、トラブルシューティング
作成時の注意点については、DATAFLOWS-AUTHORING-CORE.md の「注意点とトラブルシューティング」を参照してください。 CLI 固有の問題については、COMMON-CLI.md の「注意点とトラブルシューティング(CLI 固有)」を参照してください。 接続の検出については、authoring-cli-quickref.md § 接続の検出と検証 を参照してください。
必ず行うこと
- 新しいデータフローの初回更新の前に、すべてのエンティティのプレビューを提案する — シェルを作成し、
updateDefinition(定義を永続化します)で接続をバインドした後、更新によって具体化する前にプレビューチャートを表示したいかどうかをユーザーに尋ねます。プレビュー駆動ループでは、プレビューは代わりに、永続化するupdateDefinitionの前に実行します。承諾された場合は、mashup-preview.md § ASCII チャートプレビューに従います。メタデータのみの編集(表示名、スケジュール)の場合、またはエージェントが明示的なスキップ理由を記録した場合にのみスキップします。 - まず
az login— すべてのaz rest呼び出しはアクティブなセッションを使用します。セッションがない場合は 401 になります。 - Fabric API には
--resource "https://api.fabric.microsoft.com"を使用します。 Power BI v2(gatewayClusterDatasources)には、--resource "https://analysis.windows.net/powerbi/api"を末尾のスラッシュなしで使用します — スラッシュ付きの形式はAADSTS500011 invalid_resourceで失敗します。 - 3 つの定義パーツをすべて Base64 エンコードします —
mashup.pq+queryMetadata.json+.platform、それぞれpayloadType: "InlineBase64"です。updateDefinitionは完全な置換であり、1 つまたは 2 つのパーツのみを送信するとクエリが黙って破棄されます。 - 同期レスポンスと非同期レスポンスの両方を処理します。
POST /dataflows、updateDefinition、getDefinitionは通常は同期(200/201)を返しますが、大きなボディでは 202 + LROLocationを返すことがあります — 両方を処理してください。authoring-script-templates.md § Fabric LRO ポーリングパターンを参照してください。 queryMetadata.jsonでformatVersion: "202502"を設定し、displayNameと一致するトップレベルのnameを含めます — どちらかを省略すると、保存時の失敗や表示名の状態が古くなる原因になります。loadEnabledはオプトアウトであり、オプトインではありません。 Fabric はデフォルトで、すべてのクエリをステージング Lakehouse に自動的に読み込みます。書き込みたくないヘルパークエリにのみloadEnabled: falseを設定します。注:loadEnabled: trueも(デフォルトであるため)getDefinitionを経由したラウンドトリップでqueryMetadata.jsonから取り除かれます — 読み戻し時にこれが存在しないことはバグではありません。詳細: DATAFLOWS-AUTHORING-CORE.md § loadEnabled のセマンティクス。- コンテキストごとに正しい ID 形式を使用します。 REST の
/v1/connections操作はconnection.idのプレーンな GUID を受け取ります。queryMetadata.jsonのconnections[].connectionIdは文字列化された複合{"ClusterId":"…","DatasourceId":"…"}を受け取ります。connection-management.md § 接続 ID 形式チートシートを参照してください。 ClusterIdは list+filter で解決します。GET .../gatewayClusterDatasourcesをvalue[?id=='$CONN_ID']でフィルターします。ID ごとのルートは、クラウド接続ではPowerBIEntityNotFoundを返します。新しく作成された接続には 5〜15 秒のリトライが必要な場合があります。connection-management.md § ClusterId の解決を参照してください。executeQueryのボディはトップレベルのQueryNameフィールドを使用します(PascalCase が正式ですが、フィールド名自体はワイヤー上では大文字と小文字を区別しません — 小文字のqueryNameも評価されます)。値は、永続化された M または指定されたcustomMashupDocumentのsharedメンバーを指定する必要があります。{"queries":[…]}配列形式は常にDataflowExecuteQueryError: Invalid query nameで失敗します。誤ったクエリ名はQueryNotFoundを返します。完全なコントラクト: mashup-preview.md § リクエストボディ。- 正確で、大文字と小文字を区別する API 名を使用します。 エンドポイントは
executeQuery(単数形、executeQueriesは決して使いません)であり、リクエストボディのフィールドはcustomMashupDocument(mashupDocumentは決して使わず、base64 エンコードも決してせず — プレーンな UTF-8 の M 文字列です)です。同じ M ボディが、customMashupDocumentとして参照される保存済みのmashup.pqパーツになります。用語表: mashup-preview.md § 用語。 updateDefinition後の最初の更新では、必ずexecuteOption: "ApplyChangesIfNeeded"を使用する必要があります。 ボディ:{"executionData":{"executeOption":"ApplyChangesIfNeeded"}}。これがないと、Fabric は以前に適用された定義を更新します。- 終端の更新失敗は停止条件として扱います — デバッグループにしないでください。 更新/LRO ジョブが終端の
Failed/Cancelledに達した場合、またはバックエンドエラーがisRetriable: false(あるいはワークスペース全体のUnknownException)を伴う場合、生のエラーをそのまま報告し、停止します。これらはエージェントがリトライしても修正できないバックエンド/インフラの結果です — 更新を再トリガーしたり、ポーリングを続けたり、拡張調査を開始したりしないでください。せいぜい、修正可能な M/ソースの原因を特定するために 1 回だけexecuteQueryによる切り分けを試みてください。それで定義側の問題が明らかにならなければ、終了してエラーを提示します。 POST /v1/connectionsの前にGET /v1/connections/supportedConnectionTypesを呼び出します -- パラメーター名や資格情報の種類を決して推測しないでください。これらはコネクタ、テナント、時期によって異なります。ユーザー向けにコネクタの必須パラメーターやcredentialTypeのセットを要約する場合、正確で大文字と小文字を区別するエンドポイントパスGET /v1/connections/supportedConnectionTypesを使用します。これは純粋な参照(「コネクタ X はどのパラメーター/credentialType をサポートしていますか?」)の場合にも当てはまります。テナントに対して実際のGET /v1/connections/supportedConnectionTypesを実行してください。同梱のconnection-management.mdリファレンスはレスポンスの形状を示しますが、コネクタと時期によって異なる、テナント固有で大文字と小文字を区別する値の代わりにはなりません。- 更新の前に参照されている接続を検証します。
queryMetadata.json内の各connectionIdについて、GET /v1/connections/{id}(複合から抽出したプレーンな GUID)を実行します。更新時の不可解なEntityUserFailureは、多くの場合、接続の欠落またはアクセス不能です。connection-management.mdを参照してください。 - 資格情報を使用する M をプレビューする前に、接続をブートストラップバインドします。 最初の作成ペイロード内の
connections[]配列は、まだexecuteQueryからは見えません。まず少なくとも 1 回updateDefinitionを通じて永続化してください。詳細: mashup-preview.md § ブートストラップ分岐。 customMashupDocumentには完全なsection Section1; ...ドキュメントを送信します —executeQueryは生の式を自動的にラップしません。mashup-preview.md § customMashupDocument 形式を参照してください。updateDefinitionの前にexecuteQueryで候補の M をプレビューします — 変更がメタデータのみの場合、またはエージェントが明示的なスキップ理由を記録した場合を除きます。プレビューの成功は「M が評価される」ものとして扱い、次の更新を実際の可否判断として扱います。- JSON ボディはインラインではなく
--body "@<file>"で渡します。$env:TEMP\<name>.json(PowerShell、[IO.File]::WriteAllTextによる UTF-8 BOM なし)または/tmp/<name>.json(bash)に書き込みます。インラインの--body "<json>"は bash では脆弱で、Windows ではcmd.exeの引数パーサーが埋め込まれた引用符を壊すため動作しません。authoring-script-templates.md § PowerShell — 定義付きデータフローの作成を参照してください。 - 無人更新には
WorkspaceIdentity/ServicePrincipal資格情報を優先します。OAuth2+singleSignOnType: Noneは対話的なexecuteQueryでは機能しますが、サービスコンテキストの更新ではテナントの条件付きアクセスの下で脆弱です。サポートされている種類はsupportedConnectionTypesで確認してください。
避けるべきこと
- ユーザーにプレビューを提示せず、新しいデータフローを具体化すること(初回の更新) — M コードを読むだけでは、ユーザーはその内容が意図と一致しているか検証できません。初回の更新前(およびプレビューを使った反復作業では、永続化する
updateDefinitionの前)に、各エンティティの出力を ASCII チャートでプレビューすることを必ず提案してください。ユーザーは断ってもかまいませんが、提案は必ず行ってください。 definitionにformatプロパティを追加すること — Items API ではparts[]のみを使用します。"format": "json" を指定すると400 InvalidDefinitionFormatが返されます。- ワークスペースやデータフローの GUID をハードコードすること — REST API で取得してください(Connection セクションを参照)。
- 新たにバインドしたデータフローの検証に
GET /v1/workspaces/{ws}/items/{itemId}/connectionsを使うこと。 この API が反映するのは永続化された定義ではなく、更新によって具体化された状態であり、バインドに成功した後は 0 件を返します。getDefinitionを使い、queryMetadata.json.connections[]をデコードして検証してください。 updateDefinition/POST /dataflowsは常に LRO だと決めつけること。 通常の応答は同期型(200/201)です。上記の必須事項を参照し、両方の形式に対応してください。- 末尾にスラッシュを付けて PBI v2 トークンをリクエストすること(
--resource "https://analysis.windows.net/powerbi/api/")—AADSTS500011 invalid_resourceエラーになります。スラッシュを付けない形式を使ってください。 - クラウド接続に対して
gatewayClusterDatasources/{id}を ID 指定で使うこと —PowerBIEntityNotFoundが返されます。上記の必須事項に従い、一覧取得してからフィルタリングしてください。 executeQueryのリクエストボディに{"queries":[…]}配列形式を使うこと — 内部の大文字・小文字に関係なく、常に400 DataflowExecuteQueryError: Invalid query nameが返されます。トップレベルにQueryName(またはqueryName。フィールド名の大文字・小文字は区別されません)を指定してください。1 回の呼び出しにつき、クエリは 1 つだけ指定してください。getDefinitionにGETを使うこと — POST エンドポイントです。GETでは 405 が返されます。- 操作 URL を手動で組み立てること — 202 応答の
Locationヘッダーに従ってください。 displayNameの値を重複させること — 重複は拒否されませんが、混乱の原因になります。- 表示名で接続をバインドすること — 接続 ID が正しい情報源です。名前は変更される可能性があります。
- すべての接続にすべてのユーザーがアクセスできると思い込むこと。 可視性は呼び出し元ごとです。アクセス権のない呼び出し元に対する
GET /v1/connections/{id}は 403/404 を返すことがあります。GET /v1/connectionsの結果が空でも、接続が存在しない証拠にはなりません。 supportedConnectionTypesを含めずに接続リクエストボディを手作業で作ること — 推測で作成すると400 InvalidConnectionDetails/400 InvalidCredentialDetailsが返されます。- 生成した例やコミットするスクリプトに認証情報を平文で記載すること — 認証情報の値を平文で表示したり、コミットしたりしないでください。生成する接続ボディには
passwordReference/keyReference/tokenReference/servicePrincipalSecretReferenceだけを記載してください。 - オンプレミスゲートウェイの接続ボディを平文でテンプレート化すること —
OnPremisesGatewayでは、ゲートウェイメンバーごとに RSA で暗号化した認証情報が必要です。 - 公開済みの単一ソースのデータフローを、その場で複数ソースに変換すること — バインドの状態に不整合が生じます。新しく作成してから、古いものを廃止してください。
- プレビューしていない候補の M を
updateDefinitionで永続化すること —executeQueryは、updateDefinitionの後に更新してデバッグする方法より大幅に高速です。mashup-preview.md を参照してください。 - 本番規模のデータソースに対して上限のないプレビューを行うこと —
executeQueryは評価済みデータセットの全件を返します。プレビュー専用ドキュメントにTable.FirstN/TOP N/ 日付述語を追加し、保存前に削除してください。mashup-preview.md § Hard avoid を参照してください。 executeQueryとEvaluateQueryを混同すること。EvaluateQueryには先行する正常な更新が必要ですが、customMashupDocumentを使うexecuteQueryには必要ありません。作成時のプレビューループにはexecuteQueryを使ってください。- Windows/PowerShell でインラインの
--bodyを使うこと —cmd.exeが引用符を壊すため、必ず--body "@$env:TEMP\<name>.json"を使ってください。
推奨事項
- ブートストラップ用のバインドと保存を個別に行うより、実際の M と
connections[]を含むワンショットのupdateDefinitionを使用します。HTTP の往復を 1 回分省け、機能的にはどちらも同等です。説明を目的とする手順や、ブートストラップ時の M を本番用の M と異なるものにする場合は、2 段階の形式を使用します(例:mashup-preview.md のブートストラップブランチ)。 - 生の
curlよりaz restを使用します。トークンの取得と更新が自動で処理されます。レスポンスヘッダー(例:202 LRO のLocation)を取得する必要がある場合に限り、curlに切り替えます。az restでは取得できません。 updateDefinitionの前にgetDefinitionを実行します。読み取り、変更、書き込みの手順により、意図しないデータ損失を防げます。updateDefinitionは全体を置き換えます。updateDefinitionに?updateMetadata=trueを指定します。.platformの変更(表示名)が確実に適用されます。- JSON の操作には
jqを使用します。定義ペイロードをプログラムで構築できます。 - ジョブ実行時のパラメーターの種類には
"Automatic"を指定します。エンジンが定義から種類を推測できるようになります。 - スクリプトの再利用には環境変数(
WS_ID、DF_ID、API、RESOURCE)を使用します。 - 接続の検証はまとめて行います。更新前に
queryMetadata.json connections[]をループ処理し、GET /v1/connections/{id}を実行します。任意でPOST /v1/connections/{id}/testConnectionを実行し、更新された資格情報を検出します。 - 新しいデータフローを確定する前に、プレビューグラフを提示します。サンプルデータを ASCII グラフとして表示し、ユーザーが出力の形状と値を検証できるようにします。
トラブルシューティング
| 症状 | 対処方法 |
|---|---|
| 401 Unauthorized | az login が有効であることを確認し、--resource "https://api.fabric.microsoft.com"(または PBI v2 の場合は https://analysis.windows.net/powerbi/api 末尾にスラッシュを付けない)を確認してください。 |
getDefinition で 405 Method Not Allowed | GET ではなく POST を使用してください。 |
updateDefinition でクエリが黙って削除される | 3 つすべてのパーツ(mashup.pq、queryMetadata.json、.platform)を送信してください。 |
executeQuery → 400 DataflowExecuteQueryError: Invalid query name | リクエストボディで {"queries":[…]} 配列形式を使用すると、必ず失敗します。トップレベルの {"QueryName":"<shared>"} に切り替えてください(PascalCase が正式な形式です。フィールド名の大文字と小文字は通信時に区別されません)。 |
executeQuery → 400 DataflowExecuteQueryError: ErrorCode: QueryNotFound | QueryName の値が、永続化された M または指定された customMashupDocument のどの shared メンバーとも一致していません。getDefinition → mashup.pq をデコードしてクエリを一覧表示してください。 |
GET /items/{id}/connections がバインド成功後に 0 を返す | このエンドポイントが返すのは定義ではなく、更新によって反映された状態です。getDefinition → queryMetadata.json.connections[] をデコードして確認してください。 |
gatewayClusterDatasources/{id} から ClusterId を取得すると 404 / PowerBIEntityNotFound が返る | ID 指定のルートではクラウド接続を解決できません。一覧取得とフィルタリングを使用してください:GET .../gatewayClusterDatasources --query "value[?id=='$CONN_ID'] | [0].clusterId"。audience は https://analysis.windows.net/powerbi/api(末尾にスラッシュなし)です。新規作成した接続が反映されるまで 5~15 秒かかることがあります。再試行してください。connection-management.md § Resolving ClusterId を参照してください。 |
updateDefinition 後の初回実行で更新が失敗する(古いデータ、変更の欠落) | 定義を変更した後の初回更新では、リクエストボディに {"executionData":{"executeOption":"ApplyChangesIfNeeded"}} を含める必要があります。 |
| 更新時に "Connection not found" が発生する | queryMetadata.json から複合形式の connectionId を抽出し、DatasourceId を解析して、GET /v1/connections/{id} で確認してください。 |
updateDefinition 後に connections[] がない | バインドのないスナップショットから queryMetadata.json が読み取り・変更・書き込みによって再構築されました。更新前に再度バインドして updateDefinition を実行してください。 |
| 接続の作成とバインド後に、更新で "connection not found" が報告される | queryMetadata.json の ID 形式が誤っています。REST の id は GUID のみですが、connectionId は {"ClusterId":"…","DatasourceId":"…"} を文字列化したものです。 |
formatVersion の不一致エラー | queryMetadata.json で formatVersion: "202502" を設定してください。 |
| 高速コピーが有効にならない | mashup.pq の section の前に [StagingDefinition = [Kind = "FastCopy"]] を追加してください。 |
| LRO のポーリングで 404 が返る | Location ヘッダーの URL を使用してください。操作 URL を手動で組み立てないでください。 |
| 429 Too Many Requests | Retry-After に従い、指数バックオフを行ってください。 |
| Base64 のデコード結果が文字化けする | 末尾の改行を削除し、base64 -w0(Linux)を使用してください。 |
Windows でインラインの --body "<json>" が 400 または空のボディを返す | az.exe の起動時に cmd.exe の引数パーサーが引用符を壊します。$env:TEMP\body.json(UTF-8、BOM なし)に書き込み、--body "@$env:TEMP\body.json" を渡してください。authoring-script-templates.md § PowerShell — Create Dataflow with Definition を参照してください。 |
EntityUserFailure / "Something went wrong" が詳細なしで表示され、更新に失敗する | (1) 作成後に updateDefinition が呼び出されたことを確認してください。(2) 資格情報の種類を確認してください。OAuth2 と singleSignOnType: None の組み合わせは、テナントの条件付きアクセスが有効な環境で、無人更新に失敗することがよくあります。WorkspaceIdentity または ServicePrincipal を推奨します。(3) データフローに対して executeQuery を実行し、M とソースを切り分けてください。(4) GET https://api.powerbi.com/v1.0/myorg/groups/{ws}/dataflows/{df}/transactions(PBI v1.0)で、エンティティごとの詳細なエラーが返ることがあります。 |
例
プラットフォームに関する注意 — 以下の例は bash 用です。Windows/PowerShell では、bash のパターン(
MASHUP='...'のヒアドキュメント、echo -n | base64 -w0、tr -d '\r' | grep -i location | awk)を使うと、エスケープ処理で問題が発生しやすく、更新パターンも不安定になります。特に手間のかかる Create と Refresh の例には、PowerShell 用のバリエーションをリンクしています。PowerShell の完全なテンプレート(Create、Refresh、Validate Connections、Bind Connection、Create Cloud Connection)については、authoring-script-templates.md § PowerShell を参照してください。PowerShell では、--body "@$env:TEMP\body.json"を使い、Out-File(Windows PowerShell 5.1 では UTF-8 BOM が書き込まれ、az.exeの本文解析に失敗するため)やインラインの--body "{...}"(cmd.exeによって内容が改変されるため)を避けて、[IO.File]::WriteAllText($path, $body, [System.Text.UTF8Encoding]::new($false))で本文を書き込むことをお勧めします。
例 1:Dataflow Gen2 をゼロから作成する
プロンプト:「Web コネクタを使って公開 CSV を読み込む新しい Dataflow Gen2 を作成し、検証してください。」
エージェントの応答 — ワークフロー A の実行可能な bash 実装です。PowerShell 用のバリエーション:authoring-script-templates.md § End-to-End Smoke Test。
# Prereqs: az login, jq, base64, uuidgen. Workspace must support Dataflow Gen2.
WS_ID="<workspaceId>"
DF_NAME="my-titanic-df"
CONN_NAME="my-titanic-web-conn"
URL="https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
RES="https://api.fabric.microsoft.com"; API="$RES/v1"
PBI="https://analysis.windows.net/powerbi/api" # NO trailing slash
# Step 1: List existing connections, try to reuse by name.
CONN_ID=$(az rest --method get --resource "$RES" --url "$API/connections" \
--query "value[?displayName=='$CONN_NAME'] | [0].id" -o tsv)
# Step 2: Create if missing (Web + Anonymous; see connection-management.md for other shapes).
if [ -z "$CONN_ID" ] || [ "$CONN_ID" = "null" ]; then
BODY_FILE=$(mktemp --suffix=.json 2>/dev/null || mktemp) # GNU + BSD/macOS compatible
cat > "$BODY_FILE" <<EOF
{
"displayName": "$CONN_NAME",
"connectivityType": "ShareableCloud",
"connectionDetails": {
"type": "Web", "creationMethod": "Web",
"parameters": [{"name": "url", "dataType": "Text", "value": "$URL"}]
},
"privacyLevel": "Organizational",
"credentialDetails": {
"singleSignOnType": "None", "connectionEncryption": "NotEncrypted",
"skipTestConnection": false,
"credentials": {"credentialType": "Anonymous"}
}
}
EOF
CONN_ID=$(az rest --method post --resource "$RES" --url "$API/connections" \
--headers "Content-Type=application/json" --body "@$BODY_FILE" --query id -o tsv)
rm -f "$BODY_FILE"
fi
# Step 3: Resolve ClusterId via list+filter; retry — PBI v2 lags by 5-15s on new conns.
for i in 1 2 3 4 5 6 7 8; do
CLUSTER_ID=$(az rest --method get --resource "$PBI" \
--url "https://api.powerbi.com/v2.0/myorg/me/gatewayClusterDatasources" \
--query "value[?id=='$CONN_ID'] | [0].clusterId" -o tsv 2>/dev/null)
[ -n "$CLUSTER_ID" ] && [ "$CLUSTER_ID" != "null" ] && break
sleep $((i*3))
done
# Fail-fast: an empty ClusterId silently corrupts the composite connectionId and the
# resulting updateDefinition / refresh failures are hard to debug. Stop here instead.
if [ -z "$CLUSTER_ID" ] || [ "$CLUSTER_ID" = "null" ]; then
echo "FAIL: ClusterId not resolved for $CONN_ID after retries. Verify the connection is visible at PBI v2 (api.powerbi.com/v2.0/myorg/me/gatewayClusterDatasources)." >&2
exit 1
fi
# Step 4: Create empty dataflow shell (sync 201).
SHELL_BODY=$(mktemp --suffix=.json 2>/dev/null || mktemp)
printf '{"displayName":"%s"}' "$DF_NAME" > "$SHELL_BODY"
DF_ID=$(az rest --method post --resource "$RES" \
--url "$API/workspaces/$WS_ID/dataflows" \
--headers "Content-Type=application/json" \
--body "@$SHELL_BODY" --query id -o tsv)
rm -f "$SHELL_BODY"
# Step 5: One-shot updateDefinition — real M + composite-bound connections[] + .platform.
MASHUP='section Section1;
shared Titanic = let
Source = Csv.Document(Web.Contents("'"$URL"'"), [Delimiter=",", Encoding=65001, QuoteStyle=QuoteStyle.Csv]),
Headers = Table.PromoteHeaders(Source, [PromoteAllScalars=true])
in Headers;'
COMPOSITE_ID="{\"ClusterId\":\"$CLUSTER_ID\",\"DatasourceId\":\"$CONN_ID\"}"
QUERY_META=$(jq -n --arg name "$DF_NAME" --arg cid "$COMPOSITE_ID" --arg url "$URL" --arg qid "$(uuidgen)" '{
formatVersion: "202502",
name: $name,
queriesMetadata: { Titanic: { queryId: $qid, queryName: "Titanic" } },
connections: [ { connectionId: $cid, kind: "Web", path: $url } ]
}')
PLATFORM=$(jq -n --arg name "$DF_NAME" --arg lid "$(uuidgen)" '{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/gitIntegration/platformProperties/2.0.0/schema.json",
metadata: { type: "Dataflow", displayName: $name },
config: { version: "2.0", logicalId: $lid }
}')
MASHUP_B64=$(echo -n "$MASHUP" | base64 -w0)
META_B64=$(echo -n "$QUERY_META" | base64 -w0)
PLAT_B64=$(echo -n "$PLATFORM" | base64 -w0)
BODY_FILE=$(mktemp --suffix=.json 2>/dev/null || mktemp) # GNU + BSD/macOS compatible
cat > "$BODY_FILE" <<EOF
{"definition":{"parts":[
{"path":"mashup.pq", "payload":"${MASHUP_B64}", "payloadType":"InlineBase64"},
{"path":"queryMetadata.json", "payload":"${META_B64}", "payloadType":"InlineBase64"},
{"path":".platform", "payload":"${PLAT_B64}", "payloadType":"InlineBase64"}
]}}
EOF
az rest --method post --resource "$RES" \
--url "$API/workspaces/$WS_ID/dataflows/$DF_ID/updateDefinition?updateMetadata=true" \
--headers "Content-Type=application/json" --body "@$BODY_FILE"
rm -f "$BODY_FILE"
# Step 6: Verify connections[] persisted via getDefinition (NOT /items/{id}/connections).
# Assumes the sync 200 fast-path (typical, ~1s). If the call ever returns 202 LRO,
# az rest can't expose the Location header — switch to the curl + poll pattern from
# Example 3 / authoring-script-templates.md and decode the polled 200 body instead.
PERSISTED=$(az rest --method post --resource "$RES" \
--url "$API/workspaces/$WS_ID/dataflows/$DF_ID/getDefinition" \
--headers "Content-Length=0" \
| jq -r '.definition.parts[] | select(.path=="queryMetadata.json") | .payload' | base64 -d \
| jq -r '.connections | length')
[ "${PERSISTED:-0}" -gt 0 ] && echo "OK: connections[] persisted." || { echo "FAIL: bind missing (or getDefinition returned a 202 LRO body — see note above)." >&2; exit 1; }
# Step 7 (optional): Validate the M evaluates — top-level QueryName, PascalCase.
EQ_BODY=$(mktemp --suffix=.json 2>/dev/null || mktemp)
printf '{"QueryName":"Titanic"}' > "$EQ_BODY"
az rest --method post --resource "$RES" \
--url "$API/workspaces/$WS_ID/dataflows/$DF_ID/executeQuery" \
--headers "Content-Type=application/json" \
--body "@$EQ_BODY" --output-file /tmp/titanic.arrow
rm -f "$EQ_BODY"
# Apache Arrow stream — embedded {"Error":"..."} means failure even on HTTP 200.
grep -q '"Error":"' /tmp/titanic.arrow && { echo "executeQuery surfaced an error." >&2; exit 1; }
# Step 8 (optional): Trigger refresh with ApplyChangesIfNeeded on first run — see Example 2.
例 2:更新ジョブをトリガーする
プロンプト:「このデータフローの更新をトリガーし、完了するまでポーリングしてください。」
エージェントの応答:
# Trigger refresh (returns 202 + Location header for polling).
# jobType MUST be "Refresh"; "Pipeline" returns 400 InvalidJobType.
# On the first refresh after any updateDefinition, body MUST include executeOption=ApplyChangesIfNeeded
# (otherwise Fabric refreshes the previously-applied definition).
# Acquire $TOKEN per common/COMMON-CLI.md § Token-in-Variable Pattern (resource = https://api.fabric.microsoft.com).
LOCATION=$(curl -sS -X POST \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
--data '{"executionData":{"executeOption":"ApplyChangesIfNeeded"}}' \
"https://api.fabric.microsoft.com/v1/workspaces/${WS_ID}/dataflows/${DF_ID}/jobs/instances?jobType=Refresh" \
-o /dev/null -D - | tr -d '\r' | grep -i "^location:" | awk '{print $2}')
# Poll while the status is non-terminal. Fabric refresh job status enum:
# NotStarted / InProgress -> non-terminal, keep polling
# Completed -> success
# Failed / Cancelled -> terminal backend outcome (fatal-stop)
# Deduped -> another refresh is already running; this trigger was skipped (NOT success)
# Treat ONLY NotStarted/InProgress as non-terminal and break on anything else, so a newly-added
# terminal status surfaces immediately instead of waiting out MAX_POLLS (the contract notes more
# status values may be added over time). MAX_POLLS bounds the wait if the job never terminates.
ATTEMPT=0; MAX_POLLS="${MAX_POLLS:-60}"
while [ "$ATTEMPT" -lt "$MAX_POLLS" ]; do
STATUS=$(az rest --method get --url "$LOCATION" \
--resource "https://api.fabric.microsoft.com" --query "status" -o tsv)
echo "Status: $STATUS"
case "$STATUS" in NotStarted|InProgress) ;; *) break ;; esac
sleep 10; ATTEMPT=$((ATTEMPT + 1))
done
case "$STATUS" in
Completed) : ;; # success (exit 0)
Deduped)
# Concurrency, not success: another refresh is already running and this trigger was skipped.
# Monitor the in-flight instance instead of re-triggering. Exit non-zero so automation does not
# mistake a skipped trigger for a completed refresh.
echo "Refresh deduplicated — another instance is already running; monitor that instance instead of re-triggering."
exit 2 ;;
NotStarted|InProgress)
# Max-poll bound reached before any terminal status — a polling timeout, NOT a terminal outcome.
# Surface the raw job instance and stop; do not assume success.
echo "Polling stopped after ${MAX_POLLS} attempts with non-terminal status '$STATUS' (max-poll timeout, not a terminal outcome)."
az rest --method get --url "$LOCATION" --resource "https://api.fabric.microsoft.com"
exit 1 ;;
*) # Failed / Cancelled (or any other terminal status): a terminal backend outcome — not something
# to debug-loop. Surface the job's raw error (the job-instance body's .failureReason, an
# ErrorResponse with .errorCode / .isRetriable / .message) and STOP. Do NOT re-trigger or keep
# polling when .failureReason.isRetriable=false or the error is workspace-wide.
az rest --method get --url "$LOCATION" --resource "https://api.fabric.microsoft.com"
exit 1 ;;
esac
PowerShell 用のバリエーション(Invoke-WebRequest はレスポンスヘッダーをネイティブに公開するため、tr | grep | awk のパイプを使わずに済みます):
# Notes:
# - $Resp.Headers["Location"] returns string or string[] depending on PS version — never
# use .Location[0] (returns first character on Windows PS 5.1 plain-string case).
# - Wrap Invoke-WebRequest in try/catch on 5.1 (-SkipHttpErrorCheck is PS 7+).
# - Fabric refresh job status enum: NotStarted / InProgress (non-terminal); Completed (success);
# Failed / Cancelled (fatal); Deduped (another refresh already running — NOT success). Treat only
# NotStarted/InProgress as non-terminal and break on anything else, bounded by a max-poll count, so
# a newly-added terminal status surfaces immediately instead of waiting out $MaxPolls.
# This is distinct from the LRO operation enum (Running / Succeeded / Failed / Cancelled).
# Refresh "success" = "Completed", not "Succeeded".
# Acquire $Token per common/COMMON-CLI.md § Token-in-Variable Pattern (resource = https://api.fabric.microsoft.com).
try {
$Resp = Invoke-WebRequest -Method POST -UseBasicParsing `
-Uri "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/dataflows/$DF_ID/jobs/instances?jobType=Refresh" `
-Headers @{ Authorization = "Bearer $Token"; "Content-Type" = "application/json" } `
-Body '{"executionData":{"executeOption":"ApplyChangesIfNeeded"}}'
} catch {
Write-Error "Refresh trigger failed: $($_.Exception.Message)"; exit 1
}
$Location = $Resp.Headers["Location"]
if ($Location -is [array]) { $Location = $Location[0] }
$Attempt = 0; $MaxPolls = 60
do {
$Status = az rest --method get --url $Location `
--resource "https://api.fabric.microsoft.com" --query "status" -o tsv
Write-Host "Status: $Status"
if ($Status -notin 'NotStarted','InProgress') { break }
Start-Sleep -Seconds 10; $Attempt++
} while ($Attempt -lt $MaxPolls)
if ($Status -in 'NotStarted','InProgress') {
# Max-poll bound reached before any terminal status — a polling timeout, NOT a terminal outcome.
Write-Host "Polling stopped after $MaxPolls attempts with non-terminal status '$Status' (max-poll timeout, not a terminal outcome)."
az rest --method get --url $Location --resource "https://api.fabric.microsoft.com"
exit 1
}
switch ($Status) {
'Completed' { } # success (exit 0)
'Deduped' {
# Concurrency, not success: another refresh is already running and this trigger was skipped.
# Exit non-zero so callers don't treat a skipped trigger as a completed refresh.
Write-Host "Refresh deduplicated — another instance is already running; monitor that instance instead of re-triggering."
exit 2
}
default {
# Failed / Cancelled (or any other terminal status): a terminal backend outcome — surface the job's
# raw error (the job-instance body's .failureReason: .errorCode / .isRetriable / .message) and STOP;
# do not re-trigger or debug-loop when failureReason.isRetriable=false or the error is workspace-wide.
az rest --method get --url $Location --resource "https://api.fabric.microsoft.com"
Write-Error "Refresh terminated '$Status' (not Completed)"; exit 1
}
}
例 3:既存のデータフローの定義を変更する
プロンプト:「既存のデータフローのマッシュアップを、変更したクエリで更新してください。」
エージェントの応答 — 読み取り、変更、書き込みのループです。通常、getDefinition は同期的に 200 を返します。このテンプレートは、202 と LRO の分岐にも対応しています。
RESOURCE="https://api.fabric.microsoft.com"
# Acquire $TOKEN per common/COMMON-CLI.md § Token-in-Variable Pattern (resource = $RESOURCE).
# 1. Read current definition (sync 200 or 202 LRO — handle both).
HDR=$(mktemp); BODY=$(mktemp)
CODE=$(curl -sS -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Length: 0" \
"$RESOURCE/v1/workspaces/${WS_ID}/dataflows/${DF_ID}/getDefinition" \
-D "$HDR" -o "$BODY" -w "%{http_code}")
if [ "$CODE" = "202" ]; then
LOC=$(tr -d '\r' < "$HDR" | grep -i "^location:" | awk '{print $2}')
RETRY=$(tr -d '\r' < "$HDR" | grep -i "^retry-after:" | awk '{print $2}'); RETRY=${RETRY:-5}
while :; do
sleep "$RETRY"
OP=$(az rest --method get --resource "$RESOURCE" --url "$LOC")
case "$(echo "$OP" | jq -r '.status // empty')" in
Succeeded) DEF=$(az rest --method get --resource "$RESOURCE" --url "${LOC%/}/result"); break ;;
Failed|Cancelled) echo "ERROR: getDefinition $(echo "$OP" | jq -r '.status')" >&2; exit 1 ;;
esac
done
else
DEF=$(cat "$BODY")
fi
rm -f "$HDR" "$BODY"
# 2. Decode each part, modify mashup.pq, re-encode all 3.
MASHUP=$(echo "$DEF" | jq -r '.definition.parts[] | select(.path=="mashup.pq") | .payload' | base64 -d)
META=$( echo "$DEF" | jq -r '.definition.parts[] | select(.path=="queryMetadata.json") | .payload' | base64 -d)
PLAT=$( echo "$DEF" | jq -r '.definition.parts[] | select(.path==".platform") | .payload' | base64 -d)
NEW_MASHUP=$(echo "$MASHUP" | sed 's/old-pattern/new-pattern/') # edit M here
MASHUP_B64=$(echo -n "$NEW_MASHUP" | base64 -w0)
META_B64=$(echo -n "$META" | base64 -w0)
PLAT_B64=$(echo -n "$PLAT" | base64 -w0)
# 3. Build the updateDefinition body in a temp file (full replacement — all 3 parts).
BODY_FILE=$(mktemp --suffix=.json 2>/dev/null || mktemp) # GNU + BSD/macOS compatible
cat > "$BODY_FILE" <<EOF
{"definition":{"parts":[
{"path":"mashup.pq", "payload":"${MASHUP_B64}", "payloadType":"InlineBase64"},
{"path":"queryMetadata.json", "payload":"${META_B64}", "payloadType":"InlineBase64"},
{"path":".platform", "payload":"${PLAT_B64}", "payloadType":"InlineBase64"}
]}}
EOF
az rest --method post --resource "$RESOURCE" \
--url "$RESOURCE/v1/workspaces/${WS_ID}/dataflows/${DF_ID}/updateDefinition?updateMetadata=true" \
--headers "Content-Type=application/json" --body "@$BODY_FILE"
rm -f "$BODY_FILE"
新しい接続をバインドしますか?例 1 の手順 1~5 が、バインドと保存を行う標準的なフローです。バインドのみの手順については、authoring-cli-quickref.md § Connection Binding Quick Patterns と authoring-script-templates.md § Connection Binding Templates を参照してください。
出力の期待事項
このスキルがタスクを完了したとき、エージェントは次の内容を返す必要があります。
| 項目 | 規定 |
|---|---|
| 詳細度 | 作成または変更した内容を簡潔にまとめます(3〜10行)。 |
| 既定の形式 | ステータスレポートには Markdown を使用します。単一リソースの応答にはフェンス付き JSON コードブロックを、一覧の応答には Markdown テーブルを使用します。 |
| 副作用の開示 | 作成・変更・削除した ID と対象のワークスペース ID を明示的に報告します。ID を示さずに成功を示唆してはいけません。データフロー定義を保存または置き換えた場合は、長いコマンド本文がトランスクリプトで切り詰められ、書き込んだ部分名が失われる可能性があるため、mashup.pq、queryMetadata.json、.platform のうち、書き込んだ部分を文章で明記します。また、実際に使用した永続化パスも明記します。エンドポイントを通じて定義を保存した場合は updateDefinition、作成時に定義を指定した場合は作成呼び出し POST /v1/workspaces/{ws}/dataflows を記載します。作成 POST で定義を永続化した場合に、updateDefinition を使用したと主張してはいけません。 |
| 検証 | 完了を宣言する前に、影響を受けたリソース(データフロー、接続、ジョブインスタンス)を再度 GET し、その状態(例:provisionState、status、Completed)を提示します。 |
| エラーの提示 | いずれかの手順で 2xx 以外のステータス、LRO の Failed/Cancelled、または Arrow ストリームの {"Error":"..."} が返された場合は、未加工のエラーをそのまま伝え、処理を停止します。終端状態の更新 Failed/Cancelled、isRetriable: false のバックエンドエラー、またはワークスペース全体の UnknownException は致命的な停止条件です。報告して終了し、再実行、再ポーリング、長時間のデバッグループに入ってはいけません。 |
| プレビューの表示(ワークフロー C) | executeQuery の後、埋め込みエラーのチェックに合格した場合でも、結果の head(10) を Markdown テーブルとして、保存済みの Arrow ファイルとともにチャットに表示します。これにより、埋め込みエラー検出では見つけられないサイレントな成功バグ(フィルターによる全行の除外、列の誤り、オフバイワン、誤ったキャスト)を検出できます。スニペットと抑制ルールについては、dataflows-consumption-cli § Example 5b を参照してください。 |
| API 名 | 回答で API エンドポイントまたはリクエスト本文のフィールドに言及する場合は、言い換えたり複数形にしたりせず、正確で大文字・小文字を区別した名前(executeQuery、customMashupDocument、QueryName、mashup.pq、queryMetadata.json、GET /v1/connections/supportedConnectionTypes)を使用します。 |