mcpField
P
powerbi-authoring-cli

powerbi-authoring-cli

github.com/microsoft数据与数据库1.3k70 次安装3 周前更新
代码仓库

关于 powerbi-authoring-cli

powerbi-authoring-cli 是用于在 Fabric 中创作 Power BI 语义模型的命令行技能。它涵盖 TMDL 模型定义、刷新和数据源操作、权限及部署管道,并通过 Fabric 与 Power BI API 执行操作。

主要功能

  1. 01创建、获取和更新语义模型定义
  2. 02使用 TMDL 编写模型
  3. 03管理刷新、数据源和参数
  4. 04管理权限与部署管道
  5. 05通过独立的消费技能验证模型

适用场景

  1. 01创建或修改语义模型定义
  2. 02刷新模型并检查其数据源
  3. 03设置模型权限或在管道阶段间部署

MCP 相关

该技能主要通过 az rest 调用 Fabric 和 Power BI API。它建议使用 powerbi-modeling-mcp 对单个模型对象进行精细编辑。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/skills-for-fabric --skill powerbi-authoring-cli

安装后在 Claude Code 中输入/powerbi-authoring-cli确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
semantic-model-properties-guide.md
tmdl-advanced-features-guide.md
tmdl-authoring-guide.md

详细介绍

检查更新 — 每个会话仅执行一次(必须) 首次在会话中使用此技能时,请先运行 check-updates 技能,然后再继续。

  • GitHub Copilot CLI / VS Code:调用 check-updates 技能。
  • Claude Code / Cowork / Cursor / Windsurf / Codex:比较本地与远程的 package.json 版本。
  • 如果本会话中已执行过检查,则跳过。

重要说明

  1. 若要通过工作区名称查找工作区详情(包括其 ID):请先列出所有工作区,然后使用 JMESPath 进行筛选。
  2. 若要通过工作区 ID、项目类型和项目名称查找项目详情(包括其 ID):请先列出该工作区中此类型的所有项目,然后使用 JMESPath 进行筛选。

Power BI 语义模型创作 — CLI 技能

目录

任务参考备注
在 Fabric 中查找工作区和项目COMMON-CLI.md § 在 Fabric 中查找工作区和项目必读 — 请先阅读链接 [用于按名称查找工作区 ID,或按名称、项目类型和工作区 ID 查找项目 ID]
Fabric 拓扑和关键概念COMMON-CORE.md § Fabric 拓扑和关键概念层次结构;在 Fabric 中查找对象
环境 URLCOMMON-CORE.md § 环境 URL生产环境(公有云)
身份验证和令牌获取COMMON-CORE.md § 身份验证和令牌获取audience 错误会导致 401;委托身份与应用身份,以及令牌 audience
工具选择依据COMMON-CLI.md § 工具选择依据
身份验证方案COMMON-CLI.md § 身份验证方案az login 流程、环境检测、令牌获取和调试
通过 az rest 使用 Fabric 控制平面 APICOMMON-CLI.md § 通过 az rest 使用 Fabric 控制平面 API始终传入 --resource;包含工作区/项目操作、分页和 LRO 模式
通过 curl 访问 OneLake 数据COMMON-CLI.md § 通过 curl 访问 OneLake 数据使用 curl,而不是 az rest(令牌 audience 不同)
作业执行(CLI)COMMON-CLI.md § 作业执行运行笔记本/管道、刷新语义模型、检查/取消作业
OneLake 快捷方式COMMON-CLI.md § OneLake 快捷方式创建快捷方式;列出快捷方式;删除快捷方式
容量管理(CLI)COMMON-CLI.md § 容量管理列出容量;将工作区分配给容量
组合方案COMMON-CLI.md § 组合方案端到端的工作区→湖屋→文件、SQL 终结点→查询和笔记本执行方案
注意事项和故障排除(CLI 专属)COMMON-CLI.md § 注意事项和故障排除(CLI 专属)az rest audience、shell 转义、令牌过期
快速参考COMMON-CLI.md § 快速参考az rest 模板;令牌 Audience ↔ CLI 工具对照表
DAX 查询和元数据发现powerbi-consumption-cli只读 DAX 查询;用于创建后的验证
工具栈SKILL.md § 工具栈az rest(主要工具)、jq(JSON 解析)、base64 编码
身份验证和 API AudienceSKILL.md § 身份验证和 API Audience两种 audience:Fabric API 与 Power BI Datasets API
必须/优先/避免SKILL.md § 必须/优先/避免语义模型创作的防护措施
SemanticModel 定义和信封结构ITEM-DEFINITIONS-CORE.md § SemanticModelTMDL 格式;必需部分、信封结构、支持矩阵
TMDL 文件结构和示例SKILL.md § TMDL 文件结构必需部分、最简内容示例
TMDL CRUD(创建/获取/更新)SKILL.md § 创建语义模型创建 → 获取/下载 → 更新;包含 LRO 的完整生命周期
创作范围矩阵SKILL.md § 创作范围矩阵Fabric API 支持的内容与应避免的内容
刷新操作SKILL.md § 刷新操作触发、取消、历史记录、计划(Power BI API)
数据源和参数SKILL.md § 数据源和参数获取/更新数据源和参数
权限SKILL.md § 权限授予/更新数据集用户权限
部署管道SKILL.md § 部署管道列出阶段、获取阶段、在阶段之间部署
Agentic 工作流SKILL.md § Agentic 工作流分步流程:发现 → 创建 → 验证 → 刷新 → 确认
故障排除SKILL.md § 故障排除常见错误表:LRO、身份验证、TMDL 编码、刷新
示例SKILL.md § 示例创建模型、下载定义、刷新、部署
属性到 API 的映射semantic-model-properties-guide.md § 属性到 API 的映射将各属性类别映射到正确的 API 接口
所有者、存储模式和操作元数据semantic-model-properties-guide.md § 所有者、存储模式Power BI Datasets API 属性
刷新历史响应属性semantic-model-properties-guide.md § 刷新历史刷新详情响应字段
数据源响应属性semantic-model-properties-guide.md § 数据源连接和网关属性
DirectQuery / LiveConnection 刷新计划semantic-model-properties-guide.md § DQ 刷新计划DirectQuery/LiveConnection 计划设置
上游 Dataflow 链接semantic-model-properties-guide.md § 上游 DataflowDataflow 依赖项属性
每个表的存储模式semantic-model-properties-guide.md § 每个表的存储通过 TMDL 设置表级存储模式
TMDL 语法规则tmdl-authoring-guide.md § TMDL 语法规则Tab 缩进、对象声明、引号规则
建模最佳实践tmdl-authoring-guide.md § 建模最佳实践命名约定、列规则、度量值和 DAX 规则、格式字符串
关系tmdl-authoring-guide.md § 关系关系声明、键规则
层次结构tmdl-authoring-guide.md § 层次结构层次结构声明和键规则
Direct Lake 指南tmdl-authoring-guide.md § Direct Lake 指南Direct Lake 模式配置和限制
计算表tmdl-authoring-guide.md § 计算表基于 DAX 的计算表定义
日期/日历表tmdl-authoring-guide.md § 日期/日历表日历表设置和标记
参数tmdl-authoring-guide.md § 参数基于表达式的参数声明
注释tmdl-authoring-guide.md § 注释模型级和对象级注释
TMDL 文件布局和核心文件tmdl-advanced-features-guide.md § 文件布局目录结构、database.tmdl、model.tmdl
计算组tmdl-advanced-features-guide.md § 计算组计算组表和项
安全角色tmdl-advanced-features-guide.md § 安全角色RLS/OLS 角色定义
安全角色成员资格SKILL.md § 安全角色成员资格在 RLS 角色中添加/列出/删除用户和组(Power BI API)
翻译/区域性tmdl-advanced-features-guide.md § 翻译/区域性通过区域性文件实现本地化
透视tmdl-advanced-features-guide.md § 透视用于子集视图的透视定义
函数tmdl-advanced-features-guide.md § 函数模型中的用户定义 DAX 函数
日历对象tmdl-advanced-features-guide.md § 日历对象自动日期/时间日历表对象

工具栈

工具作用安装
az CLI主要工具:使用 az rest 调用 Fabric 和 Power BI REST API,使用 az login 进行身份验证。大多数开发环境中已预装
jq解析 az rest 响应中的 JSON已预装或安装非常简单
base64(Linux/macOS)/ [Convert]::ToBase64String(PowerShell)为定义负载编码 TMDL 文件内容内置

Agent 检查 — 首次操作前验证:

az version 2>/dev/null || echo "INSTALL: https://learn.microsoft.com/cli/azure/install-azure-cli"

身份验证与 API 受众

此技能使用两种不同的 API 受众。使用错误的受众会返回 401 错误。

API受众(--resource)用途
Fabric Items APIhttps://api.fabric.microsoft.com创建/获取/更新/删除语义模型定义、列出项、轮询 LRO
Power BI Datasets APIhttps://analysis.windows.net/powerbi/api刷新、数据源、参数、权限、部署管道
# Fabric Items API — semantic model definition operations
az rest --method post \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/semanticModels" \
  ...

# Power BI Datasets API — refresh, data sources, permissions
az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "https://api.powerbi.com/v1.0/myorg/groups/$WS_ID/datasets/$DATASET_ID/refreshes" \
  ...

必须做 / 优先做 / 避免做

必须做
  • 生成任何 TMDL 前,先阅读相关的 TMDL 参考章节——至少阅读 TMDL 语法规则和建模最佳实践。如果任务涉及关系、层次结构、计算组、安全角色或翻译,还要阅读 tmdl-authoring-guide.md 和 tmdl-advanced-features-guide.md 中的相应章节。不要凭记忆生成 TMDL。
  • 始终为 az rest 传入 --resource——省略它会导致身份验证静默失败。根据上表使用正确的受众。
  • 对发往 Power BI Datasets API 且带有 --body 的 POST/PATCH/PUT 调用,始终传入 --headers "Content-Type=application/json"——省略它会导致 Unsupported Media Type 错误。
  • 在 updateDefinition 中包含所有定义部分,包括已修改和未修改的部分。API 会替换整个定义;省略任何部分都会将其删除。
  • 绝不要在 updateDefinition 负载中包含 .platform——它是 Git 集成元数据,会导致错误。
  • 轮询 LRO,直到操作完成——createItemWithDefinition、getDefinition 和 updateDefinition 会返回带有 Operation-Id 标头的 202 Accepted。持续轮询,直到进入终止状态。
  • 对 TMDL 内容进行 Base64 编码——定义部分中的所有 payload 值都必须经过 Base64 编码。
  • 名称包含特殊字符时使用单引号括起——名称中包含空格、.、=、: 或 ' 时,必须在 TMDL 中用单引号括起。
  • 创建语义模型前,确认工作区具备容量——调用 GET /v1/workspaces/{id} 并检查 capacityId。
优先做
  • 新建语义模型时,优先使用 createItemWithDefinition(单次 POST),而非先创建再更新。
  • 优先使用 TMDL 格式,而非 TMSL——TMDL 基于文本、便于比较差异,也是 Fabric 的首选格式。
  • TMDL 表文件中优先放置度量值,再放置列——遵循 TMDL 约定。
  • 使用三个反引号括起多行 DAX——提升复杂表达式的可读性。
  • 将精细化更改交由 powerbi-modeling-mcp 处理——添加/修改单个度量值、列或关系时,MCP 服务比完整定义往返操作更高效。
  • 更新前先获取定义——始终先检索当前定义,修改后再 POST 回去,以避免覆盖并发更改。
  • 交叉参考 powerbi-consumption-cli 进行创建后的验证——运行 DAX 查询,验证度量值、关系和数据。
避免
  • 小幅更改时使用 updateDefinition — 完整定义往返开销很大;单个对象编辑应转到 powerbi-modeling-mcp。
  • 创建报表 — 此技能不支持。报表需要单独的定义格式(PBIR/PBIR-Legacy)。
  • 在新对象上添加 lineageTag — TMDL 会自动生成 lineage tag;手动添加会导致冲突。
  • 在 TMDL 中使用 // 注释 — 不支持。请改用 /// 描述。
  • 在 TMDL 中使用 description 属性 — 请改用对象上方的 /// 语法。
  • 硬编码工作区/项目 ID — 通过 REST API 动态解析(参见 COMMON-CLI.md § 在 Fabric 中查找工作区和项目)。
  • 在 updateDefinition 中仅发送修改部分 — API 会替换完整定义;缺少的部分会被删除。

TMDL 文件结构

完整定义封装和部件路径请参见 ITEM-DEFINITIONS-CORE.md § SemanticModel。

createItemWithDefinition 和 updateDefinition 所需的 TMDL 部件:

部件路径内容必需
definition.pbism语义模型连接设置是
definition/database.tmdl数据库属性(兼容性级别)是
definition/model.tmdl模型属性(区域设置、默认汇总方式)是
definition/tables/<TableName>.tmdl每个表的列、度量值、分区是(≥1)

重要:updateDefinition 必须包含所有部件,包括已修改和未修改的部件。API 会替换整个定义。更新负载中绝不要包含 .platform。

TMDL 语法规则、命名约定和建模最佳实践请参见 tmdl-authoring-guide.md。


最小 TMDL 内容示例

definition.pbism
{
    "version": "4.2",
    "settings": {
        "qnaEnabled": true
    }
}
database.tmdl
database
	compatibilityLevel: 1702
	compatibilityMode: powerBI
model.tmdl
model Model
	culture: en-US
	defaultPowerBIDataSourceVersion: powerBI_V3
	discourageImplicitMeasures

注意:导入模式模型必须设置 defaultPowerBIDataSourceVersion: powerBI_V3。否则,API 会返回 Import from JSON supported for V3 models only。

导入模式表
table Customer

	/// Total number of customers
	measure '# Customers' = COUNTROWS(Customer)
		formatString: #,##0

	column CustomerId
		dataType: int64
		isHidden
		isKey
		summarizeBy: none
		sourceColumn: CustomerId

	column 'Customer Name'
		dataType: string
		sourceColumn: CustomerName

	partition Customer = m
		mode: import
		source =
			let
				Source = Sql.Database(#"Server", #"Database"),
				Customer = Source{[Schema="dbo", Item="Customer"]}[Data]
			in
				Customer
Direct Lake 表
expression DL_Lakehouse =
	let
		Source = AzureStorage.DataLake("https://onelake.dfs.fabric.microsoft.com/<WorkspaceId>/<LakehouseId>", [HierarchicalNavigation=true])
	in
		Source

table Sales

	/// Total revenue
	measure 'Total Sales' = ```
			SUMX(
				Sales,
				Sales[Quantity] * Sales[UnitPrice]
			)
			```
		formatString: \$#,##0.00

	column SalesKey
		dataType: int64
		isHidden
		isKey
		summarizeBy: none
		sourceColumn: sales_key

	column Quantity
		dataType: int64
		sourceColumn: quantity

	column UnitPrice
		dataType: decimal
		summarizeBy: none
		sourceColumn: unit_price

	partition Sales = entity
		mode: directLake
		source
			entityName: Sales
			schemaName: dbo
			expressionSource: DL_Lakehouse

创建语义模型

完整生命周期:编写 TMDL → 进行 base64 编码 → 构造负载 → POST → 轮询 LRO。

根据 COMMON-CLI.md § 项目 CRUD 操作 和 ITEM-DEFINITIONS-CORE.md § 定义封装:

WS_ID="<workspaceId>"

# 1. Base64-encode each TMDL file
PBISM=$(base64 -w 0 < definition.pbism)
DB=$(base64 -w 0 < definition/database.tmdl)
MODEL=$(base64 -w 0 < definition/model.tmdl)
TABLE=$(base64 -w 0 < definition/tables/Customer.tmdl)

# 2. Construct payload and create — use --verbose to capture HTTP status and LRO headers
cat > /tmp/body.json << EOF
{
  "displayName": "MySalesModel",
  "definition": {
    "format": "TMDL",
    "parts": [
      {"path": "definition.pbism", "payload": "$PBISM", "payloadType": "InlineBase64"},
      {"path": "definition/database.tmdl", "payload": "$DB", "payloadType": "InlineBase64"},
      {"path": "definition/model.tmdl", "payload": "$MODEL", "payloadType": "InlineBase64"},
      {"path": "definition/tables/Customer.tmdl", "payload": "$TABLE", "payloadType": "InlineBase64"}
    ]
  }
}
EOF
az rest --method post --verbose \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/semanticModels" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

PowerShell — 请使用 [Convert]::ToBase64String([System.IO.File]::ReadAllBytes("file")),而不是 base64 -w 0。

如果响应为 202 Accepted,请使用 COMMON-CLI.md § 长时间运行的操作中的 LRO 模式进行轮询。


获取/下载定义

获取 TMDL 定义,用于备份、迁移或检查。getDefinition 是 POST(不是 GET)。

WS_ID="<workspaceId>"
MODEL_ID="<semanticModelId>"

# 1. Request definition — may return 200 (inline) or 202 (LRO)
RESPONSE=$(az rest --method post --verbose \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/semanticModels/$MODEL_ID/getDefinition?format=TMDL" \
  --body '{}' \
  --output json 2>/dev/null)

# 2. If 202, poll the Location header URL until Succeeded, then GET /result

# 3. Decode each part
echo "$RESPONSE" | jq -r '.definition.parts[] | .path + " " + .payload' | \
while read -r path payload; do
  mkdir -p "$(dirname "$path")"
  echo "$payload" | base64 -d > "$path"
done

更新定义

重要规则:必须包含所有部件(已修改和未修改)。绝不要包含 .platform。API 会替换整个定义,省略的部件会被删除。

WS_ID="<workspaceId>"
MODEL_ID="<semanticModelId>"

# 1. Get current definition (see Get/Download Definition above)
# 2. Modify the relevant TMDL files
# 3. Re-encode ALL parts and POST

cat > /tmp/body.json << EOF
{
  "definition": {
    "format": "TMDL",
    "parts": [
      {"path": "definition.pbism", "payload": "$PBISM", "payloadType": "InlineBase64"},
      {"path": "definition/database.tmdl", "payload": "$DB", "payloadType": "InlineBase64"},
      {"path": "definition/model.tmdl", "payload": "$MODEL", "payloadType": "InlineBase64"},
      {"path": "definition/tables/Customer.tmdl", "payload": "$TABLE", "payloadType": "InlineBase64"}
    ]
  }
}
EOF
az rest --method post \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/semanticModels/$MODEL_ID/updateDefinition" \
  --body @/tmp/body.json

仅当必须包含 .platform 文件以通过定义更新显示名称或描述时,才使用 ?updateMetadata=true 查询参数。


创作范围矩阵

操作支持情况方法
使用 TMDL 创建语义模型✅使用定义调用 POST /v1/workspaces/{id}/semanticModels
获取/下载 TMDL 定义✅POST .../semanticModels/{id}/getDefinition?format=TMDL
更新完整 TMDL 定义✅POST .../semanticModels/{id}/updateDefinition
删除语义模型✅DELETE /v1/workspaces/{id}/semanticModels/{id}
刷新数据集✅Power BI Datasets API(第 4 阶段)
添加/修改单个度量值或列⚠️ 路由至 powerbi-modeling-mcp完整定义往返效率低
创建报表❌不在范围内——使用单独的定义格式(PBIR)

刷新操作

所有刷新操作都使用 Power BI Datasets API 受众(https://analysis.windows.net/powerbi/api)。

WS_ID="<workspaceId>"
DATASET_ID="<semanticModelId>"
PBI="https://api.powerbi.com/v1.0/myorg"

# Trigger full refresh
cat > /tmp/body.json << 'EOF'
{"notifyOption": "NoNotification"}
EOF
az rest --method post --verbose \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/refreshes" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

# Get refresh history (latest first)
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/refreshes?\$top=5"

# Cancel an in-progress refresh
az rest --method delete \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/refreshes/<refreshId>"

# Get refresh schedule
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/refreshSchedule"

# Update refresh schedule
cat > /tmp/body.json << 'EOF'
{
  "value": {
    "enabled": true,
    "days": ["Monday", "Wednesday", "Friday"],
    "times": ["02:00", "14:00"],
    "localTimeZoneId": "UTC"
  }
}
EOF
az rest --method patch \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/refreshSchedule" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

数据源和参数

# Get data sources for a dataset
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/datasources"

# Get parameters
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/parameters"

# Update parameters
cat > /tmp/body.json << 'EOF'
{
  "updateDetails": [
    {"name": "Server", "newValue": "newserver.database.windows.net"},
    {"name": "Database", "newValue": "ProductionDB"}
  ]
}
EOF
az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/Default.UpdateParameters" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

更新参数或数据源凭据后,触发刷新以使更改生效。


权限

# List dataset users
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/users"

# Grant dataset permissions to a user
cat > /tmp/body.json << 'EOF'
{
  "identifier": "[email protected]",
  "principalType": "User",
  "datasetUserAccessRight": "Read"
}
EOF
az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/users" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

# Update existing user permissions
cat > /tmp/body.json << 'EOF'
{
  "identifier": "[email protected]",
  "principalType": "User",
  "datasetUserAccessRight": "ReadReshare"
}
EOF
az rest --method put \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/users" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

权限级别:Read、ReadReshare、ReadExplore、ReadReshareExplore。


安全角色成员资格

在 TMDL 中定义 RLS/OLS 角色后(参见安全角色),使用 Power BI Datasets API 将用户和组分配到这些角色。

PBI="https://api.powerbi.com/v1.0/myorg"

# List members of a security role
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/users" \
  | jq '[.value[] | select(.datasetUserAccessRight == "Read" and .roles != null)]'

# Add a user to a security role
cat > /tmp/body.json << 'EOF'
{
  "identifier": "[email protected]",
  "principalType": "User",
  "datasetUserAccessRight": "Read",
  "roles": ["SalesRegion"]
}
EOF
az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/users" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

# Add a security group to a role
cat > /tmp/body.json << 'EOF'
{
  "identifier": "<group-object-id>",
  "principalType": "Group",
  "datasetUserAccessRight": "Read",
  "roles": ["SalesRegion"]
}
EOF
az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/users" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

# Update role membership (e.g., move user to a different role)
cat > /tmp/body.json << 'EOF'
{
  "identifier": "[email protected]",
  "principalType": "User",
  "datasetUserAccessRight": "Read",
  "roles": ["EuropeOnly"]
}
EOF
az rest --method put \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/users" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

roles 数组接受一个或多个角色名称,这些名称必须与语义模型 TMDL 中定义的角色一致。用户/组还必须至少拥有数据集的 Read 权限。principalType 可以是 User、Group 或 App。


部署管道

部署管道使用 Fabric API 受众(https://api.fabric.microsoft.com)。

FABRIC="https://api.fabric.microsoft.com/v1"

# List deployment pipelines
az rest --method get \
  --resource "https://api.fabric.microsoft.com" \
  --url "$FABRIC/deploymentPipelines"

# Get pipeline stages
az rest --method get \
  --resource "https://api.fabric.microsoft.com" \
  --url "$FABRIC/deploymentPipelines/<pipelineId>/stages"

# Deploy from one stage to the next (e.g., Dev → Test)
cat > /tmp/body.json << 'EOF'
{
  "sourceStageOrder": 0,
  "targetStageOrder": 1,
  "items": [
    {
      "sourceItemId": "<semanticModelId>",
      "itemType": "SemanticModel"
    }
  ],
  "options": {
    "allowCreateArtifact": true,
    "allowOverwriteArtifact": true
  }
}
EOF
az rest --method post \
  --resource "https://api.fabric.microsoft.com" \
  --url "$FABRIC/deploymentPipelines/<pipelineId>/deploy" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json

省略 items 数组即可部署阶段中的所有项目。部署调用会返回 202 Accepted——使用 LRO 模式进行轮询。


Agent 工作流

工具选择优先级
  1. powerbi-modeling-mcp 可用 → 使用 MCP 工具进行细粒度对象更改(度量值、列、关系)
  2. MCP 不可用,但 TMDL 文件可用 → 直接编辑 TMDL 文件,通过 az rest updateDefinition 进行部署
  3. MCP 不可用,且只有工作区 → 使用此技能:getDefinition → 编辑 TMDL → updateDefinition
工作流步骤
  1. 发现工作区 → 列出工作区,按名称查找目标工作区(参见 COMMON-CLI.md § 查找工作区和项目)
  2. 列出语义模型 → 调用 GET /v1/workspaces/{id}/semanticModels 查找现有模型或确认名称可用
  3. 分析源架构 → 通过 SQL、DAX 或 Lakehouse 元数据检查源表/列,为星型架构设计提供依据
  4. 设计星型架构 → 确定事实表和维度表,定义关系键,规划度量值
  5. 编写 TMDL 文件 → 按照最小 TMDL 内容示例和 tmdl-authoring-guide.md 创建 definition.pbism、database.tmdl、model.tmdl 和表文件
  6. 创建关系 → 在创建依赖这些关系的度量值之前,先在表 TMDL 文件中定义关系
  7. 创建度量值 → 为所有可聚合值添加显式度量值,并设置 formatString
  8. 部署 → 对所有部分进行 base64 编码 → POST createItemWithDefinition(参见创建语义模型)
  9. 验证 → 运行验证检查(见下文)
  10. 刷新 → 通过刷新操作触发数据集刷新
  11. 使用 DAX 验证 → 使用 powerbi-consumption-cli 对已部署的模型运行 DAX 查询
创建后的验证
  • TMDL 结构 — 验证所有必需部分均已存在(definition.pbism、database.tmdl、model.tmdl、≥1 个表)
  • 测试度量值 — 通过 DAX 为每个度量值运行 EVALUATE { [Measure Name] }
  • 验证关系 — 确认基数、交叉筛选方向,以及两侧的 dataType 相匹配
  • 验证列 — 确认 sourceColumn 映射以及 dataType 与源架构相匹配
  • 检查重复项 — 不存在重复的度量值名称或孤立对象

故障排除

提前终止规则:如果 getDefinition 返回 404 EntityNotFound(针对可列出或 GET 的项),且 Power BI 刷新 API 返回 403 Forbidden,并带有 "identity None",请立即停止重试——用户几乎可以确定在工作区中只有 Viewer 角色。通过调用 GET /v1/workspaces/{id}/roleAssignments 验证;如果该调用也返回 403 InsufficientWorkspaceRole,请告知用户需要 Contributor 或更高角色。不要尝试不同的 URL 格式、端点或参数进行重试——问题在于权限,而非 API 用法。

症状原因解决方法
Power BI API 上出现带有 "identity None" 的 403 Forbidden用户具有 Viewer 角色——刷新、数据源和权限 API 要求 Contributor 或更高角色立即停止。 请用户申请工作区的 Contributor/Member/Admin 角色
getDefinition 返回 404 EntityNotFound,但项存在于列表中权限不足伪装成 404——getDefinition 要求 Contributor 或更高角色首先检查工作区角色;不要尝试不同的 URL 格式重试
roleAssignments 返回 403 InsufficientWorkspaceRole用户在工作区中是 Viewer确认用户具有 Viewer 角色——所有创作操作和大多数读取操作都会被阻止
Fabric API 上出现 401 Unauthorized--resource 错误或缺失使用 --resource "https://api.fabric.microsoft.com"
Power BI API 上出现 401 Unauthorized受众错误使用 --resource "https://analysis.windows.net/powerbi/api"
getDefinition 返回 411 Length Required缺少请求正文传入 --body '{}'——getDefinition 是 POST 请求
LRO 轮询始终未完成长时间操作期间令牌过期在轮询循环中重新获取令牌;增大 Retry-After 间隔
返回 202 Accepted,但没有结果未跟进 LRO 直至完成轮询 Location 标头 URL,直到状态为 Succeeded,然后 GET /result
create/update 时出现 TMDL 验证错误TMDL 内容存在语法错误查看 tmdl-authoring-guide.md 中的 TMDL 规则;编码前进行验证
updateDefinition 后缺少部分内容仅发送了修改过的部分每次更新都必须包含所有部分(已修改和未修改的部分)
update 中出现包含 .platform 的错误默认不接受 .platform从各部分中移除 .platform,或使用 ?updateMetadata=true
Base64 解码后内容乱码编码错误或换行处理不当使用 base64 -w 0(不换行)或 [Convert]::ToBase64String()
刷新因数据源错误而失败凭据已过期或参数错误检查数据源和参数;如有需要,更新凭据
部署管道失败工作区未分配到阶段部署前将工作区分配到管道阶段
新对象出现 lineageTag 冲突手动添加了 lineageTag从新对象中移除 lineageTag——它会自动生成
测试度量值时出现 DAX 错误度量值名称大小写不匹配DAX 度量值名称区分大小写;请确保完全匹配
尝试通过 DAX 使用 INFO.ROLES() / INFO.ROLEMEMBERSHIPS() 获取角色成员DAX INFO 函数无法可靠地返回角色成员数据,可能返回空结果或不完整结果改用 Power BI REST API:GET /v1.0/myorg/groups/{workspaceId}/datasets/{datasetId}/users,并按 roles 字段筛选(参见安全角色成员)

示例

从 TMDL 创建语义模型
WS_ID="<workspaceId>"

# Encode all TMDL files
PBISM=$(base64 -w 0 < definition.pbism)
DB=$(base64 -w 0 < definition/database.tmdl)
MODEL=$(base64 -w 0 < definition/model.tmdl)
CUSTOMER=$(base64 -w 0 < definition/tables/Customer.tmdl)
SALES=$(base64 -w 0 < definition/tables/Sales.tmdl)

cat > /tmp/body.json << EOF
{
  "displayName": "SalesModel",
  "definition": {
    "parts": [
      {"path": "definition.pbism", "payload": "$PBISM", "payloadType": "InlineBase64"},
      {"path": "definition/database.tmdl", "payload": "$DB", "payloadType": "InlineBase64"},
      {"path": "definition/model.tmdl", "payload": "$MODEL", "payloadType": "InlineBase64"},
      {"path": "definition/tables/Customer.tmdl", "payload": "$CUSTOMER", "payloadType": "InlineBase64"},
      {"path": "definition/tables/Sales.tmdl", "payload": "$SALES", "payloadType": "InlineBase64"}
    ]
  }
}
EOF
az rest --method post --verbose \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/semanticModels" \
  --headers "Content-Type=application/json" \
  --body @/tmp/body.json
下载语义模型定义
WS_ID="<workspaceId>"
MODEL_ID="<semanticModelId>"

# Get definition (may return 202 — follow LRO)
RESULT=$(az rest --method post \
  --resource "https://api.fabric.microsoft.com" \
  --url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/semanticModels/$MODEL_ID/getDefinition?format=TMDL" \
  --body '{}' --output json)

# Decode and save all parts
echo "$RESULT" | jq -r '.definition.parts[] | .path + "\t" + .payload' | \
while IFS=$'\t' read -r path payload; do
  mkdir -p "$(dirname "$path")"
  echo "$payload" | base64 -d > "$path"
  echo "Saved: $path"
done
触发刷新并检查状态
WS_ID="<workspaceId>"
DATASET_ID="<semanticModelId>"
PBI="https://api.powerbi.com/v1.0/myorg"

# Trigger refresh
cat > /tmp/body.json << 'EOF'
{"type": "Full"}
EOF
az rest --method post \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/refreshes" \
  --body @/tmp/body.json

# Check latest refresh status
az rest --method get \
  --resource "https://analysis.windows.net/powerbi/api" \
  --url "$PBI/groups/$WS_ID/datasets/$DATASET_ID/refreshes?\$top=1"
通过管道部署到生产环境
FABRIC="https://api.fabric.microsoft.com/v1"
PIPELINE_ID="<pipelineId>"

# Deploy from Test (stage 1) to Production (stage 2)
cat > /tmp/body.json << 'EOF'
{
  "sourceStageOrder": 1,
  "targetStageOrder": 2,
  "items": [
    {"sourceItemId": "<semanticModelId>", "itemType": "SemanticModel"}
  ],
  "options": {
    "allowCreateArtifact": true,
    "allowOverwriteArtifact": true
  }
}
EOF
az rest --method post \
  --resource "https://api.fabric.microsoft.com" \
  --url "$FABRIC/deploymentPipelines/$PIPELINE_ID/deploy" \
  --body @/tmp/body.json

评论

支持 Markdown