dataflows-save-as-authoring-cli

作者: microsoft

更新检查 — 每个会话一次(必需) 当此技能在会话中首次使用时,先运行检查更新技能再继续。

npx skills add https://github.com/microsoft/skills-for-fabric --skill dataflows-save-as-authoring-cli

Update Check — ONCE PER SESSION (mandatory) The first time this skill is used in a session, run the check-updates skill before proceeding.

  • GitHub Copilot CLI / VS Code: invoke the check-updates skill.
  • Claude Code / Cowork / Cursor / Windsurf / Codex: compare local vs remote package.json version.
  • Skip if the check was already performed earlier in this session.

CRITICAL NOTES

  1. To find the workspace details (including its ID) from workspace name: list all workspaces and, then, use JMESPath filtering
  2. To find the item details (including its ID) from workspace ID, item type, and item name: list all items of that type in that workspace and, then, use JMESPath filtering

dataflows-save-as-authoring-cli — Dataflow Save-As Gen1 → Gen2.1 CI/CD via CLI

A save-as companion for creating upgraded Gen2.1 copies from Power BI Gen1 dataflows using readiness assessment and guarded execution.

We currently cannot perform an in-place migration of your dataflow. We can use save-as to create an upgraded Gen2.1 copy while preserving the original Gen1 dataflow.

Table of Contents

TaskReferenceNotes
Finding Workspaces and Items in FabricCOMMON-CLI.md § Finding Workspaces and ItemsMandatoryREAD link first
Fabric Topology & Key ConceptsCOMMON-CORE.md § Fabric Topology
Environment URLsCOMMON-CORE.md § Environment URLs
Authentication & Token AcquisitionCOMMON-CORE.md § AuthenticationWrong audience = 401
Core Control-Plane REST APIsCOMMON-CORE.md § Core REST APIsPagination, LRO polling, rate limits
Tool Selection RationaleCOMMON-CLI.md § Tool Selection
Authentication RecipesCOMMON-CLI.md § Auth Recipesaz login flows and token acquisition
Fabric Control-Plane API via az restCOMMON-CLI.md § az restAlways pass --resource
Gotchas & Troubleshooting (CLI)COMMON-CLI.md § Gotchasaz rest audience, shell escaping
Quick ReferenceCOMMON-CLI.md § Quick RefToken audience / tool matrix
Dataflow Definition StructureDATAFLOWS-AUTHORING-CORE.md § Definition3-part format for Gen2 CI/CD
Consumption Capability MatrixDATAFLOWS-CONSUMPTION-CORE.md § CapabilitiesRead-only discovery patterns
Upgrade CLI Quick Referenceupgrade-cli-quickref.mdAll az rest one-liners for scanning & save-as
Risk Assessment Guiderisk-assessment-guide.mdRisk signal detection logic & API calls

Tool Stack

ToolRoleInstall
az CLIPrimary: Auth (az login), REST API calls (az rest) against both Fabric and Power BI APIs.Pre-installed in most dev environments
jqParse and filter JSON responses (dataflow lists, risk signal extraction).Pre-installed or trivial
base64Decode dataflow definitions for inspection.Built into bash / [Convert]::ToBase64String() in PowerShell

Agent check — verify before first operation:

az --version 2>/dev/null || echo "INSTALL: https://aka.ms/install-azure-cli"
jq --version 2>/dev/null || echo "INSTALL: apt-get install jq OR brew install jq"

Authentication & API Audiences

This skill uses two distinct API audiences. Using the wrong audience returns 401.

APIAudience (--resource)Use For
Fabric Items APIhttps://api.fabric.microsoft.comList Gen2 dataflows (Fabric-native), workspace discovery
Power BI REST APIhttps://analysis.windows.net/powerbi/apiGen1 dataflow discovery, saveAsNativeArtifact, data sources, upstream dataflows, Admin API scanning
# Fabric Items API — list Gen2 dataflows in a workspace
az rest --method get \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/dataflows"

# Power BI REST API — list all dataflows (Gen1 + Gen2) in a workspace
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "https://api.powerbi.com/v1.0/myorg/groups/$WS_ID/dataflows"

# Power BI Admin API — list all dataflows tenant-wide (requires admin role)
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "https://api.powerbi.com/v1.0/myorg/admin/dataflows"

Phase 1 — Awareness & Readiness

Goal: "Should I use save-as, and what will happen when I create a Gen2.1 copy?"

Agentic Workflow: Discover → Assess → Classify → Report

Follow this sequence for every save-as assessment:

  1. Discover — Scan workspace(s) to inventory all dataflows, identifying Gen1 vs Gen2
  2. Assess — For each Gen1 dataflow, check seven risk signals
  3. Classify — Assign a readiness category: ✅ Safe / ⚠️ Manual followups / ❌ Blocked
  4. Report — Output a Save-As Readiness Snapshot (markdown table + JSON)

Step 1: Discover — Identify Gen1 Dataflows

The Power BI REST API returns a generation property (value 1 or 2) on each dataflow. This is the preferred detection method — a single API call per workspace.

Non-Admin Path (per workspace)

WS_ID="<workspaceId>"
RESOURCE_PBI="https://analysis.windows.net/powerbi/api"

# List all dataflows — the `generation` property distinguishes Gen1 from Gen2
ALL_DATAFLOWS=$(az rest --method get \
  --resource "$RESOURCE_PBI" \
  --url "https://api.powerbi.com/v1.0/myorg/groups/$WS_ID/dataflows" \
  --query "value[].{id:objectId, name:name, generation:generation, modelUrl:modelUrl, configuredBy:configuredBy}" -o json)

# Filter Gen1 dataflows
echo "$ALL_DATAFLOWS" | jq '[.[] | select(.generation == 1)]'

# Filter Gen2 dataflows
echo "$ALL_DATAFLOWS" | jq '[.[] | select(.generation == 2)]'

Tip: A modelUrl pointing to dfs.core.windows.net additionally indicates BYOSA (customer-managed storage) — a save-as blocker.

Admin Path (tenant-wide)

Requires Fabric administrator role or service principal with Tenant.Read.All scope. Rate limited to 200 requests/hour.

RESOURCE_PBI="https://analysis.windows.net/powerbi/api"

# List ALL dataflows in the tenant
ADMIN_DATAFLOWS=$(az rest --method get \
  --resource "$RESOURCE_PBI" \
  --url "https://api.powerbi.com/v1.0/myorg/admin/dataflows" \
  --query "value[].{id:objectId, name:name, workspaceId:workspaceId, modelUrl:modelUrl, configuredBy:configuredBy}" \
  -o json)

# Filter Gen1 dataflows — those with a modelUrl indicate CDM/Gen1 storage
# Note: Admin API may not expose the `generation` property; use modelUrl as fallback
echo "$ADMIN_DATAFLOWS" | jq '[.[] | select(.modelUrl != null and .modelUrl != "")]'

Note: The Admin API supports $filter, $top, and $skip for pagination on large tenants.

Step 2: Assess — Check Risk Signals

For each Gen1 dataflow found, evaluate seven risk signals. See risk-assessment-guide.md for detailed API calls.

#Risk SignalDetection MethodImpact
1Incremental refreshCheck dataflow definition for incremental refresh policy configuration⚠️ Schedule migrates in disabled state; must re-enable and validate
2BYOSA / Custom ADLS Gen2 storageCheck modelUrl — if points to customer storage account (not Power BI managed)❌ Data stays in old storage; Gen2 CI/CD uses Fabric-managed storage
3Power Automate / API triggersCheck for external orchestration referencing the Gen1 dataflow ID⚠️ All integrations must update to new Gen2 artifact ID
4Downstream pipeline dependenciesCheck Fabric pipelines for dataflow activity references⚠️ Pipeline activities reference dataflow by ID; must re-bind
5Linked / computed entitiesInspect dataflow definition for entity references to other dataflows⚠️/❌ Cross-dataflow references may break if source dataflows are not saved first
6DirectQuery connectionsInspect data source types in definition❌ DirectQuery not supported in Gen2 CI/CD dataflows
7Caller is not owner / insufficient roleCompare configuredBy against az account show --query user.name -o tsv — or attempt call and catch DataflowUnauthorizedErrorsaveAsNativeArtifact requires the caller to be the dataflow owner or have Contributor/Admin in the source workspace; Viewer/Member without ownership cannot execute save-as

Step 3: Classify — Readiness Categories

CategoryCriteriaAction
SafeNo risk signals detectedCreate a Gen2.1 save-as copy with saveAsNativeArtifact
⚠️ Manual followupsRisk signals 1, 3, 4, or 5 (non-blocking)Execute save-as, then remediate flagged issues
BlockedRisk signals 2, 6, or 7 (blocking)Cannot execute save-as until blocker is resolved

Tip — detect ownership before save-as: The configuredBy field in the dataflow list response contains the owner's email. Compare it against the currently logged-in user (az account show --query user.name -o tsv). If they don't match and your workspace role is below Contributor, flag the dataflow as ❌ Blocked (signal 7) and escalate to the owner.

Step 4: Report — Save-As Readiness Snapshot

Markdown Output (terminal)

## Save-As Readiness Snapshot
| Workspace | Dataflow | Type | Readiness | Risk Signals | Recommendation |
|---|---|---|---|---|---|
| Sales Analytics | SalesETL | Gen1 | ✅ Safe | None | Save as Gen2.1 copy now |
| Sales Analytics | CustomerLoad | Gen1 | ⚠️ Manual | Incremental refresh, Pipeline dep | Save as Gen2.1 copy, then re-enable schedule & update pipeline |
| Finance | FinanceDaily | Gen1 | ❌ Blocked | BYOSA storage | Resolve storage dependency first |

JSON Output (automation)

{
  "snapshotDate": "2025-04-13T10:00:00Z",
  "summary": { "total": 3, "safe": 1, "manual": 1, "blocked": 1 },
  "dataflows": [
    {
      "workspaceName": "Sales Analytics",
      "workspaceId": "...",
      "dataflowName": "SalesETL",
      "dataflowId": "...",
      "type": "Gen1",
      "readiness": "safe",
      "riskSignals": [],
      "recommendation": "Save as Gen2.1 copy now",
      "saveAsPath": "saveAsNativeArtifact"
    }
  ]
}

Save JSON to file: pipe to jq '.' > readiness-snapshot.json


Execute with Guardrails

Goal: Invoke save-as and capture outcomes safely.

Gen1 → Gen2.1 CI/CD: saveAsNativeArtifact API

POST https://api.powerbi.com/v1.0/myorg/groups/{groupId}/dataflows/{gen1DataflowId}/saveAsNativeArtifact

This is a Preview API. It creates a new Gen2.1 CI/CD artifact copy while preserving the original Gen1 dataflow.

WS_ID="<workspaceId>"
GEN1_ID="<gen1DataflowId>"

# Write body to a temp file — az rest wraps inline --body in an envelope
# on some platforms, causing "saveAsRequest is a required parameter" errors.
cat > /tmp/save-as-body.json <<'EOF'
{
  "displayName": "MyDataflow_Gen2CICD",
  "description": "Saved as Gen2.1 copy from Gen1",
  "includeSchedule": true,
  "targetWorkspaceId": "<targetWorkspaceId>"
}
EOF

az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "https://api.powerbi.com/v1.0/myorg/groups/$WS_ID/dataflows/$GEN1_ID/saveAsNativeArtifact" \
  --headers "Content-Type=application/json" \
  --body @/tmp/save-as-body.json

Gotcha — inline body: Passing JSON inline via --body '{...}' can cause az rest to wrap the payload in an extra envelope, resulting in "saveAsRequest is a required parameter" errors. Always use file-based body (--body @file.json) for this endpoint.

Gotcha — Windows az.cmd: On Windows, omit -o json from saveAsNativeArtifact calls — the flag produces "A value that is not valid (json) was specified for the outputFormat parameter" when routed through az.cmd. Capture output without -o json and parse with ConvertFrom-Json in PowerShell, or pipe to jq in bash.

Gotcha — not idempotent (duplicate artifacts on retry): saveAsNativeArtifact creates a new artifact every time it is called. If a batch is interrupted and re-run, you will end up with multiple copies in the target workspace. To make retries safe: (1) check whether a Gen2 artifact with the intended name already exists before calling, or (2) include a timestamp in displayName and treat each run as a distinct artifact.

Gotcha — owner permissions: You must be the dataflow owner or have Contributor/Admin in the source workspace to call saveAsNativeArtifact. If you are only a Viewer or Workspace Member who does not own the dataflow, the API returns DataflowUnauthorizedError. Ask the dataflow owner or a workspace admin to run the save-as operation for those dataflows.

Request parameters:

ParameterTypeRequiredDescription
displayNamestring (max 200)NoName for new artifact. Auto-generated with _copy1 suffix if omitted
descriptionstring (max 4000)NoDescription. Copied from source if omitted
includeSchedulebooleanNoCopy refresh schedule in disabled state
targetWorkspaceIdstring (uuid)NoTarget workspace. Same workspace if omitted

Response: 200 OK with SaveAsNativeDataflowResponse:

  • artifactMetadata — full metadata of the new Gen2 CI/CD artifact (including objectId, provisionState)
  • errors[] — non-fatal warning codes (save-as succeeds even if these occur):
    • FailedToCopySchedule — schedule could not be copied
    • SetDataflowOriginFailed — origin tracking not set
    • ConnectionsUpdateFailed — connection strings could not be updated to Fabric format

Gen2 → Gen2 CI/CD: In-Place Upgrade

NOT YET AVAILABLE — This API is not available in the current public surface. This skill will be updated when the endpoint is published. Do not attempt to call a non-existent endpoint.

Post-Save-As Validation Checklist

Run these checks after save-as before any Gen1 cleanup:

  • Confirm artifactMetadata.provisionState reaches Active.
  • Review errors[] in SaveAsNativeDataflowResponse and create follow-up tasks for each warning.
  • Confirm the new artifact exists in the target workspace and has expected name/description.
  • Verify dependent orchestration (pipelines, flows, API callers) is updated to the new artifact ID.
  • Only trigger refresh when the user explicitly approves.

Must/Prefer/Avoid

MUST DO

  • Always pass --resource to az rest — use the correct audience per the API table above. Wrong audience = silent 401.
  • Always include --headers "Content-Type=application/json" on POST calls to the Power BI REST API.
  • Use file-based body for saveAsNativeArtifact — pass --body @file.json instead of inline JSON. Inline --body '{...}' can cause az rest to wrap the payload in an extra envelope, producing "saveAsRequest is a required parameter" errors.
  • On Windows, omit -o json on saveAsNativeArtifact calls — use ConvertFrom-Json in PowerShell or pipe to jq instead. The -o json flag fails with "A value that is not valid (json)" error when routed through az.cmd.
  • Verify you are the dataflow owner or Contributor before save-assaveAsNativeArtifact returns DataflowUnauthorizedError for non-owners who are only Workspace Members or Viewers.
  • Check for existing Gen2 artifacts before retryingsaveAsNativeArtifact is not idempotent; interrupted batch runs create duplicate copies on retry. Either verify the target name is absent before calling, or use a unique timestamped displayName per run.
  • Scan before save-as — always run the readiness scan before execution.
  • Never refresh without explicit user consent — the Gen2 CI/CD artifact schedule is created in disabled state for safety.
  • Check errors[] in saveAsNativeArtifact response — save-as may succeed with non-fatal warnings.
  • Verify provisionState is Active after save-as — poll the artifact metadata until terminal state.
  • Preserve the original Gen1 dataflowsaveAsNativeArtifact leaves the Gen1 intact. Do not delete it until post-save-as validation passes.

PREFER

  • Admin API for tenant-wide scanning — more efficient than workspace-by-workspace for large tenants.
  • JSON output for automation — markdown is for human review, JSON for scripting and CI/CD integration.
  • Topological save-as order — save upstream dataflows (with linked entities) before downstream consumers.
  • Readiness-first execution — do not skip readiness assessment before save-as.
  • generation property for Gen1 detection — the Power BI REST API returns generation: 1 or generation: 2 on each dataflow. Use this single-API-call approach over cross-API comparison.
  • modelUrl check as secondary signal — dataflows with a modelUrl pointing to dfs.core.windows.net are Gen1 using customer storage (BYOSA blocker).

AVOID

  • Saving blocked (❌) dataflows — resolve BYOSA storage and DirectQuery issues first.
  • Batch save-as without review — always review the readiness snapshot before saving multiple dataflows.
  • Hardcoded workspace/dataflow IDs — resolve dynamically via REST API.
  • Ignoring non-fatal errorsFailedToCopySchedule, ConnectionsUpdateFailed, etc. require manual follow-up.
  • Calling the Gen2→Gen2 CI/CD in-place save-as API — it does not exist yet. Do not fabricate endpoints.
  • Deleting Gen1 artifacts without explicit user consent — never delete Gen1 dataflows unless the user explicitly approves deletion, even after post-save-as validation confirms data integrity.
  • Using -o json with saveAsNativeArtifact on Windows — omit the flag; capture raw output and parse it explicitly.
  • Re-running batch save-as scripts without idempotency checks — always verify the target artifact doesn't already exist to avoid duplicate copies in the workspace.

Examples

Example 1: Full Phase 1 — Readiness Scan for a Single Workspace

Prompt: "Scan my Sales workspace for Gen1 dataflows and show me a readiness snapshot"

Agent response:

# Step 1 — Resolve workspace ID
WS_ID=$(az rest --method get \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces" \
  --query "value[?displayName=='Sales'].id" -o tsv)

# Step 2 — List all dataflows with generation property
ALL_DFS=$(az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "https://api.powerbi.com/v1.0/myorg/groups/$WS_ID/dataflows" -o json)

# Step 3 — Filter Gen1 dataflows by generation property
GEN1_DFS=$(echo "$ALL_DFS" | jq '[.value[] | select(.generation == 1) |
  {id: .objectId, name: .name, generation: .generation, modelUrl: .modelUrl}]')

echo "Gen1 dataflows found: $(echo $GEN1_DFS | jq length)"
echo "$GEN1_DFS" | jq '.'

Example 2: Save-As a Gen1 Dataflow to Gen2.1

Prompt: "Migrate or upgrade the SalesETL Gen1 dataflow in my Sales workspace"

Agent response:

WS_ID="<workspaceId>"
GEN1_ID="<gen1DataflowId>"

# Write body to file (avoids az rest envelope wrapping)
cat > /tmp/save-as-body.json <<'EOF'
{"displayName": "SalesETL_Gen2CICD", "includeSchedule": true}
EOF

# Execute save-as
RESPONSE=$(az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "https://api.powerbi.com/v1.0/myorg/groups/$WS_ID/dataflows/$GEN1_ID/saveAsNativeArtifact" \
  --headers "Content-Type=application/json" \
  --body @/tmp/save-as-body.json)

# Check result
echo "$RESPONSE" | jq '{
  newId: .artifactMetadata.objectId,
  state: .artifactMetadata.provisionState,
  errors: .errors
}'

Example 3: Tenant-Wide Admin Scan

Prompt: "Show me all Gen1 dataflows across the entire tenant"

Agent response:

# Requires Fabric administrator role
ALL_DFS=$(az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "https://api.powerbi.com/v1.0/myorg/admin/dataflows" -o json)

# Gen1 dataflows have a modelUrl
echo "$ALL_DFS" | jq '[.value[] | select(.modelUrl != null and .modelUrl != "") |
  {id: .objectId, name: .name, workspace: .workspaceId, 
   owner: .configuredBy, storage: .modelUrl}]'

来自 microsoft 的更多技能

oss-growth
microsoft
OSS增长黑客角色
official
microsoft-foundry
microsoft
端到端部署、评估和管理Foundry代理:Docker构建、ACR推送、托管/提示代理创建、容器启动、批量评估、持续评估、提示优化工作流、agent.yaml、从追踪中整理数据集。用途:将代理部署到Foundry、托管代理、创建代理、调用代理、评估代理、运行批量评估、持续评估、持续监控、持续评估状态、优化提示、改进提示、提示优化器、优化代理指令、改进代理...
officialdevelopmentdevops
azure-ai
microsoft
用于Azure AI:搜索、语音、OpenAI、文档智能。支持搜索、向量/混合搜索、语音转文字、文字转语音、转录、OCR。适用场景:AI搜索、查询搜索、向量搜索、混合搜索、语义搜索、语音转文字、文字转语音、转录、OCR、文字转语音。
officialdevelopmentapi
azure-deploy
microsoft
对已准备好的应用程序执行Azure部署,这些程序需包含现有的.azure/deployment-plan.md和基础设施文件。当用户要求创建新应用程序时,请勿使用此技能——应改用azure-prepare。此技能运行azd up、azd deploy、terraform apply和az deployment命令,并内置错误恢复机制。需要来自azure-prepare的.azure/deployment-plan.md以及来自azure-validate的已验证状态。适用场景:"运行azd up"、"运行azd deploy"、"执行部署"...
officialdevopsaws
azure-storage
microsoft
Azure存储服务,包括Blob存储、文件共享、队列存储、表存储和Data Lake。解答关于存储访问层(热、冷、冷、归档)的问题,说明各层的使用场景及对比。提供对象存储、SMB文件共享、异步消息传递、NoSQL键值存储和大数据分析。包含生命周期管理。用途:Blob存储、文件共享、队列存储、表存储、Data Lake、上传文件、下载Blob、存储账户、访问层等。
officialdevelopmentdatabase
azure-diagnostics
microsoft
使用AppLens、Azure Monitor、资源健康和安全分类调试Azure生产问题。适用场景:调试生产问题、排查应用服务、应用服务CPU过高、应用服务部署失败、排查容器应用、排查函数、排查AKS、kubectl无法连接、kube-system/CoreDNS故障、Pod挂起、CrashLoop、节点未就绪、升级失败、分析日志、KQL、洞察、镜像拉取失败、冷启动问题、健康探测失败……
officialdevopsdevelopment
azure-prepare
microsoft
为Azure应用准备部署(基础设施Bicep/Terraform、azure.yaml、Dockerfile)。用于创建/现代化或创建+部署;不用于跨云迁移(使用azure-cloud-migrate)。请勿用于:copilot-sdk应用(使用azure-hosted-copilot-sdk)。适用场景:"创建应用"、"构建Web应用"、"创建API"、"创建无服务器HTTP API"、"创建前端"、"创建后端"、"构建服务"、"现代化应用"、"更新应用"、"添加身份验证"、"添加缓存"、"托管在Azure上"、"创建并...
officialdevelopmentdevops
azure-validate
microsoft
部署前对Azure就绪状态进行验证。对配置、基础设施(Bicep或Terraform)、RBAC角色分配、托管标识权限及先决条件进行深度检查,然后再部署。适用场景:验证我的应用、检查部署就绪状态、运行预检、验证配置、检查是否可部署、验证azure.yaml、验证Bicep、部署前测试、排查部署错误、验证Azure Functions、验证函数应用、验证无服务器...
officialdevopstesting