关于 powerbi-authoring-cli
powerbi-authoring-cli 是用于在 Fabric 中创作 Power BI 语义模型的命令行技能。它涵盖 TMDL 模型定义、刷新和数据源操作、权限及部署管道,并通过 Fabric 与 Power BI API 执行操作。
主要功能
- 01创建、获取和更新语义模型定义
- 02使用 TMDL 编写模型
- 03管理刷新、数据源和参数
- 04管理权限与部署管道
- 05通过独立的消费技能验证模型
适用场景
- 01创建或修改语义模型定义
- 02刷新模型并检查其数据源
- 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.mdtmdl-advanced-features-guide.mdtmdl-authoring-guide.md详细介绍
检查更新 — 每个会话仅执行一次(必须) 首次在会话中使用此技能时,请先运行 check-updates 技能,然后再继续。
- GitHub Copilot CLI / VS Code:调用
check-updates技能。- Claude Code / Cowork / Cursor / Windsurf / Codex:比较本地与远程的 package.json 版本。
- 如果本会话中已执行过检查,则跳过。
重要说明
- 若要通过工作区名称查找工作区详情(包括其 ID):请先列出所有工作区,然后使用 JMESPath 进行筛选。
- 若要通过工作区 ID、项目类型和项目名称查找项目详情(包括其 ID):请先列出该工作区中此类型的所有项目,然后使用 JMESPath 进行筛选。
Power BI 语义模型创作 — CLI 技能
目录
工具栈
| 工具 | 作用 | 安装 |
|---|---|---|
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 API | https://api.fabric.microsoft.com | 创建/获取/更新/删除语义模型定义、列出项、轮询 LRO |
| Power BI Datasets API | https://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 工作流
工具选择优先级
powerbi-modeling-mcp可用 → 使用 MCP 工具进行细粒度对象更改(度量值、列、关系)- MCP 不可用,但 TMDL 文件可用 → 直接编辑 TMDL 文件,通过
az restupdateDefinition 进行部署 - MCP 不可用,且只有工作区 → 使用此技能:getDefinition → 编辑 TMDL → updateDefinition
工作流步骤
- 发现工作区 → 列出工作区,按名称查找目标工作区(参见 COMMON-CLI.md § 查找工作区和项目)
- 列出语义模型 → 调用
GET /v1/workspaces/{id}/semanticModels查找现有模型或确认名称可用 - 分析源架构 → 通过 SQL、DAX 或 Lakehouse 元数据检查源表/列,为星型架构设计提供依据
- 设计星型架构 → 确定事实表和维度表,定义关系键,规划度量值
- 编写 TMDL 文件 → 按照最小 TMDL 内容示例和 tmdl-authoring-guide.md 创建
definition.pbism、database.tmdl、model.tmdl和表文件 - 创建关系 → 在创建依赖这些关系的度量值之前,先在表 TMDL 文件中定义关系
- 创建度量值 → 为所有可聚合值添加显式度量值,并设置
formatString - 部署 → 对所有部分进行 base64 编码 → POST createItemWithDefinition(参见创建语义模型)
- 验证 → 运行验证检查(见下文)
- 刷新 → 通过刷新操作触发数据集刷新
- 使用 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