关于 dataflows-save-as-authoring-cli
用于通过命令行评估并执行 Power BI Gen1 Dataflow 到 Gen2.1 的 Save-As 流程,适合负责 Fabric 数据流升级与 CI/CD 的人员。它先扫描风险并生成就绪报告,再以保留原始数据流的方式创建副本。
主要功能
- 01发现并区分 Gen1 与 Gen2 数据流
- 02评估七类迁移风险
- 03生成就绪状态报告
- 04创建 Gen2.1 Save-As 副本
- 05对执行过程设置防护
适用场景
- 01批量筛查工作区中的 Gen1 数据流
- 02迁移前识别阻断项与后续处理事项
- 03保留原数据流并创建 Gen2.1 副本
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ skills-for-fabric --skill dataflows-save-as-authoring-cli安装后在 Claude Code 中输入/dataflows-save-as-authoring-cli确认已加载。
附带文件references/risk-assessment-guide.mdreferences/upgrade-cli-quickref.md
详细介绍
更新检查——每个会话仅执行一次(必须) 首次在会话中使用此技能时,必须先运行 check-updates 技能,然后再继续。
- GitHub Copilot CLI / VS Code:调用
check-updates技能。- Claude Code / Cowork / Cursor / Windsurf / Codex:比较本地与远程的 package.json 版本。
- 如果本会话中已执行过检查,则跳过。
关键说明
- 要通过工作区名称查找工作区详情(包括其 ID):先列出所有工作区,然后使用 JMESPath 进行筛选。
- 要通过工作区 ID、项类型和项名称查找项详情(包括其 ID):先列出该工作区中该类型的所有项,然后使用 JMESPath 进行筛选。
代际边界——强制停止(必须) 此技能仅执行从 Gen1 到 Gen2.1 的另存为操作。对于源代际为 Gen2,或尚未确定源代际的执行请求,说明目前没有公开的另存为或原位升级端点,并在调用 API 前停止。这不妨碍执行只读就绪情况扫描,以发现并分类 Gen1 候选项。 不要将“选择最接近的端点并继续”理解为获准导出定义并创建副本,不要自动调用创作技能,也不要修改任何内容。请用户澄清预期结果,并明确批准任何单独记录的替代方案。
dataflows-save-as-authoring-cli — 通过 CLI 对 Dataflow 执行 Gen1 → Gen2.1 另存为 CI/CD
一个另存为辅助工具,可通过就绪情况评估和受保护的执行,从 Power BI Gen1 dataflow 创建已升级的 Gen2.1 副本。
目前无法对你的 dataflow 执行原位迁移。我们可以使用另存为创建已升级的 Gen2.1 副本,同时保留原始 Gen1 dataflow。
目录
| 任务 | 参考 | 备注 |
|---|---|---|
| 在 Fabric 中查找工作区和项目 | COMMON-CLI.md § Finding Workspaces and Items | 必读 — 请先阅读链接 |
| Fabric 拓扑和关键概念 | COMMON-CORE.md § Fabric Topology | |
| 环境 URL | COMMON-CORE.md § Environment URLs | |
| 身份验证和令牌获取 | COMMON-CORE.md § Authentication | 受众错误 = 401 |
| 核心控制平面 REST API | COMMON-CORE.md § Core REST APIs | 分页、LRO 轮询、速率限制 |
| 工具选择依据 | COMMON-CLI.md § Tool Selection | |
| 身份验证方案 | COMMON-CLI.md § Auth Recipes | az login 流程和令牌获取 |
通过 az rest 调用 Fabric 控制平面 API | COMMON-CLI.md § az rest | 始终传入 --resource |
| 注意事项和故障排除(CLI) | COMMON-CLI.md § Gotchas | az rest 受众、Shell 转义 |
| 快速参考 | COMMON-CLI.md § Quick Ref | 令牌受众 / 工具矩阵 |
| Dataflow 定义结构 | DATAFLOWS-AUTHORING-CORE.md § Definition | Gen2 CI/CD 的三部分格式 |
| 消耗能力矩阵 | DATAFLOWS-CONSUMPTION-CORE.md § Capabilities | 只读发现模式 |
| Upgrade CLI 快速参考 | upgrade-cli-quickref.md | 用于扫描和另存为的所有 az rest 单行命令 |
| 风险评估指南 | risk-assessment-guide.md | 风险信号检测逻辑和 API 调用 |
工具栈
| 工具 | 作用 | 安装 |
|---|---|---|
az CLI | 主要工具:身份验证(az login),以及针对 Fabric 和 Power BI API 的 REST API 调用(az rest)。 | 大多数开发环境中已预装 |
jq | 解析和筛选 JSON 响应(dataflow 列表、风险信号提取)。 | 已预装或安装非常简单 |
base64 | 解码 dataflow 定义以供检查。 | bash 内置 / PowerShell 中的 [Convert]::ToBase64String() |
Agent 检查 — 首次操作前请验证:
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"
身份验证和 API 受众
此技能使用两个不同的 API 受众。使用错误的受众会返回 401。
| API | 受众(--resource) | 用途 |
|---|---|---|
| Fabric Items API | https://api.fabric.microsoft.com | 列出 Gen2 dataflow(Fabric 原生),发现工作区 |
| Power BI REST API | https://analysis.windows.net/powerbi/api | 发现 Gen1 dataflow、saveAsNativeArtifact、数据源、上游 dataflow、Admin API 扫描 |
# 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"
阶段 1 — 了解情况并做好准备
目标:“我应该使用另存为吗?创建 Gen2.1 副本时会发生什么?”
Agent 工作流:发现 → 评估 → 分类 → 报告
每次评估另存为操作时,都按以下顺序执行:
- 发现 — 扫描工作区,清点所有 dataflow,并识别 Gen1 和 Gen2
- 评估 — 检查每个 Gen1 dataflow 的七个风险信号
- 分类 — 指定就绪类别:✅ 安全 / ⚠️ 需要后续手动处理 / ❌ 已阻止
- 报告 — 输出另存为就绪情况摘要(Markdown 表格 + JSON)
步骤 1:发现 — 识别 Gen1 数据流
Power BI REST API 会在每个数据流中返回一个 generation 属性(值为 1 或 2)。这是首选检测方法——每个工作区只需调用一次 API。
非管理员路径(每个工作区)
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)]'
提示:如果
modelUrl指向dfs.core.windows.net,则还表示使用了 BYOSA(客户管理的存储)——这是阻止另存为的因素。
管理员路径(整个租户范围)
需要 Fabric 管理员角色,或具有 Tenant.Read.All 范围的服务主体。每小时限流 200 次请求。
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 != "")]'
注意:对于大型租户,Admin API 支持使用
$filter、$top和$skip进行分页。
步骤 2:评估 — 检查风险信号
对于发现的每个 Gen1 数据流,评估七项风险信号。有关详细的 API 调用,请参阅 risk-assessment-guide.md。
| # | 风险信号 | 检测方法 | 影响 |
|---|---|---|---|
| 1 | 增量刷新 | 检查数据流定义中的增量刷新策略配置 | ⚠️ 计划迁移后将处于禁用状态;必须重新启用并验证 |
| 2 | BYOSA / 自定义 ADLS Gen2 存储 | 检查 modelUrl — 如果指向客户的存储帐户(而非 Power BI 管理的存储) | ❌ 数据仍留在旧存储中;Gen2 CI/CD 使用 Fabric 管理的存储 |
| 3 | Power Automate / API 触发器 | 检查是否有引用 Gen1 数据流 ID 的外部编排 | ⚠️ 所有集成都必须更新为新的 Gen2 项目 ID |
| 4 | 下游管道依赖项 | 检查 Fabric 管道中是否有数据流活动引用 | ⚠️ 管道活动通过 ID 引用数据流;必须重新绑定 |
| 5 | 链接实体 / 计算实体 | 检查数据流定义中对其他数据流的实体引用 | ⚠️/❌ 如果源数据流未先另存为,跨数据流引用可能会失效 |
| 6 | DirectQuery 连接 | 检查定义中的数据源类型 | ❌ Gen2 CI/CD 数据流不支持 DirectQuery |
| 7 | 调用者不是所有者 / 角色权限不足 | 将 configuredBy 与 az account show --query user.name -o tsv 进行比较,或尝试调用并捕获 DataflowUnauthorizedError | ❌ saveAsNativeArtifact 要求调用者是数据流所有者,或在源工作区中具有参与者/管理员角色;不拥有数据流的查看者/成员无法执行另存为 |
步骤 3:分类 — 就绪情况类别
| 类别 | 条件 | 操作 |
|---|---|---|
| ✅ 安全 | 未检测到风险信号 | 使用 saveAsNativeArtifact 创建 Gen2.1 另存为副本 |
| ⚠️ 需要手动跟进 | 风险信号 1、3、4 或 5(非阻止因素) | 执行另存为,然后修复标记的问题 |
| ❌ 受阻 | 风险信号 2、6 或 7(阻止因素) | 解决阻止因素前无法执行另存为 |
提示 — 另存为前检测所有权:数据流列表响应中的
configuredBy字段包含所有者的电子邮件地址。将其与当前登录用户(az account show --query user.name -o tsv)进行比较。如果两者不匹配,且你的工作区角色低于参与者,则将该数据流标记为 ❌ 受阻(信号 7),并升级给所有者处理。
步骤 4:报告 — 另存为就绪情况快照
Markdown 输出(终端)
## 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 输出(自动化)
{
"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"
}
]
}
将 JSON 保存到文件:通过管道传递给
jq '.' > readiness-snapshot.json
设置防护措施后执行
目标:调用另存为并安全地记录结果。
Gen1 → Gen2.1 CI/CD:saveAsNativeArtifact API
POST https://api.powerbi.com/v1.0/myorg/groups/{groupId}/dataflows/{gen1DataflowId}/saveAsNativeArtifact
这是一个预览版 API。它会创建一份新的 Gen2.1 CI/CD 工件副本,同时保留原始 Gen1 数据流。
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
注意 — 内联请求体:通过
--body '{...}'内联传入 JSON 可能导致az rest为负载额外包装一层,从而出现"saveAsRequest is a required parameter"错误。此端点始终使用基于文件的请求体(--body @file.json)。
注意 — Windows
az.cmd:在 Windows 上调用saveAsNativeArtifact时,省略-o json——通过az.cmd调用时,此标志会导致"A value that is not valid (json) was specified for the outputFormat parameter"。不使用-o json捕获输出,然后在 PowerShell 中用ConvertFrom-Json解析,或在 bash 中通过管道传给jq。
注意 — 非幂等(重试会生成重复工件):每次调用
saveAsNativeArtifact都会创建一个新工件。如果批处理被中断后重新运行,目标工作区中会出现多个副本。为确保重试安全:(1) 调用前检查是否已存在名称符合预期的 Gen2 工件,或 (2) 在displayName中加入时间戳,并将每次运行视为单独的工件。
注意 — 所有者权限:调用
saveAsNativeArtifact时,你必须是数据流所有者,或在源工作区中拥有贡献者/管理员权限。如果你只是查看者或不拥有该数据流的工作区成员,API 会返回DataflowUnauthorizedError。请让数据流所有者或工作区管理员为这些数据流执行另存为操作。
请求参数:
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
displayName | string (max 200) | 否 | 新工件的名称。若省略,则自动生成并添加 _copy1 后缀 |
description | string (max 4000) | 否 | 描述。若省略,则从源工件复制 |
includeSchedule | boolean | 否 | 复制刷新计划,但将其设为禁用状态 |
targetWorkspaceId | string (uuid) | 否 | 目标工作区。若省略,则使用同一工作区 |
响应:200 OK,返回 SaveAsNativeDataflowResponse:
artifactMetadata— 新 Gen2 CI/CD 工件的完整元数据(包括objectId、provisionState)errors[]— 非致命警告代码(即使出现这些警告,另存为操作也会成功):FailedToCopySchedule— 无法复制计划SetDataflowOriginFailed— 未设置来源跟踪信息ConnectionsUpdateFailed— 无法将连接字符串更新为 Fabric 格式
Gen2 → Gen2 CI/CD:原位升级
尚不可用 — 当前公开的 API 尚不提供此 API。此技能将在端点发布后更新。请勿尝试调用不存在的端点。
另存为后的验证清单
另存为后、清理任何 Gen1 内容前,运行以下检查:
- 确认
artifactMetadata.provisionState达到Active。 - 检查
SaveAsNativeDataflowResponse中的errors[],并为每条警告创建后续任务。 - 确认新工件已存在于目标工作区,且名称和描述符合预期。
- 确认依赖的编排(管道、流、API 调用方)已更新为新的工件 ID。
- 仅在用户明确批准后才触发刷新。
必须/优先/避免
必须执行
- 始终向
az rest传递--resource— 根据上方的 API 表使用正确的受众。受众错误会导致静默 401。 - 调用 Power BI REST API 的 POST 方法时,始终包含
--headers "Content-Type=application/json"。 - 对
saveAsNativeArtifact使用基于文件的请求正文 — 传递--body @file.json,而不是内联 JSON。内联--body '{...}'可能导致az rest在负载外再包装一层信封,从而产生"saveAsRequest is a required parameter"错误。 - 在 Windows 上调用
saveAsNativeArtifact时,省略-o json— 在 PowerShell 中使用ConvertFrom-Json,或通过管道传递给jq。通过az.cmd执行时,-o json标志会因"A value that is not valid (json)"错误而失败。 - 在执行另存为之前,确认你是数据流所有者或 Contributor — 对于仅具有 Workspace Member 或 Viewer 身份的非所有者,
saveAsNativeArtifact会返回DataflowUnauthorizedError。 - 重试前检查是否已存在 Gen2 项目 —
saveAsNativeArtifact不是幂等操作;中断的批处理运行会在重试时创建重复副本。调用前请确认目标名称不存在,或为每次运行使用唯一的时间戳displayName。 - 另存为之前先扫描 — 执行前始终运行就绪状态扫描。
- 未经用户明确同意,绝不刷新 — 为安全起见,Gen2 CI/CD 项目计划会以禁用状态创建。
- 检查
saveAsNativeArtifact响应中的errors[]— 另存为可能成功,但同时返回非致命警告。 - 另存为后确认
provisionState为Active— 轮询项目元数据,直到达到终止状态。 - 保留原始 Gen1 数据流 —
saveAsNativeArtifact会保留 Gen1 数据流。在另存为后的验证通过之前,不要删除它。
优先采用
- 使用 Admin API 扫描整个租户 — 对大型租户而言,比逐个工作区扫描更高效。
- 自动化使用 JSON 输出 — Markdown 供人工审查,JSON 用于脚本和 CI/CD 集成。
- 按拓扑顺序执行另存为 — 先另存为上游数据流(包含链接实体),再处理下游使用方。
- 先评估就绪状态再执行 — 另存为之前不要跳过就绪状态评估。
- 使用
generation属性检测 Gen1 — Power BI REST API 会为每个数据流返回generation: 1或generation: 2。优先采用这种单次 API 调用方式,而不是跨 API 比较。 - 将
modelUrl检查作为辅助信号 —modelUrl指向dfs.core.windows.net的数据流是使用客户存储的 Gen1 数据流(BYOSA 阻碍因素)。
避免
- 另存为被阻止(❌)的数据流 — 先解决 BYOSA 存储和 DirectQuery 问题。
- 未经审查就批量另存为 — 批量保存多个数据流之前,始终审查就绪状态快照。
- 硬编码工作区/数据流 ID — 通过 REST API 动态解析。
- 忽略非致命错误 —
FailedToCopySchedule、ConnectionsUpdateFailed等错误需要手动跟进处理。 - 调用 Gen2→Gen2 CI/CD 原位另存为 API — 该 API 尚不存在。不要捏造端点。
- 未经用户明确同意就删除 Gen1 项目 — 除非用户明确批准删除,否则绝不删除 Gen1 数据流,即使另存为后的验证已确认数据完整性也不例外。
- 在 Windows 上对
saveAsNativeArtifact使用-o json— 省略该标志;捕获原始输出并显式解析。 - 未进行幂等性检查就重新运行批量另存为脚本 — 始终确认目标项目尚不存在,以避免在工作区中创建重复副本。
示例
示例 1:完整阶段 1 — 扫描单个工作区的就绪状态
提示词:“扫描我的 Sales 工作区,查找 Gen1 数据流并展示就绪状态快照”
Agent 响应:
# 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 '.'
示例 2:将 Gen1 数据流另存为 Gen2.1
提示词:“迁移或升级我 Sales 工作区中的 SalesETL Gen1 数据流”
Agent 响应:
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
}'
示例 3:租户范围的管理员扫描
提示词:“显示整个租户中的所有 Gen1 数据流”
Agent 响应:
# 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}]'