skills/powerbi-report-management/SKILL.md
Manage Power BI report workspace items in Microsoft Fabric via `az rest` CLI against the Fabric REST API. Use when the user wants to: (1) create reports from PBIR definitions, (2) get or download report definitions, (3) update report definitions or properties, (4) list workspace reports, (5) delete reports. For report layout authoring (pages, visuals, filters, formatting), use `powerbi-report-authoring`. Triggers: upload Power BI report, download PBIR definition, publish Power BI report to Fabric, manage Power BI reports.
npx skillsauth add microsoft/skills-for-fabric powerbi-report-managementInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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-updatesskill.- 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
- To find the workspace details (including its ID) from workspace name: list all workspaces and, then, use JMESPath filtering
- 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
Manage Power BI reports in Microsoft Fabric workspaces using az rest against
the Fabric REST API. This skill covers the full CRUD lifecycle for report items
and their PBIR definitions.
Scope: Report item CRUD and definition management only. For report layout authoring (pages, visuals, filters, formatting), use
powerbi-report-authoring.
Boundary: This skill transports PBIR definitions to and from Fabric. PBIR content authoring remains owned by
powerbi-report-authoring.
This skill is one of three that partition the Power BI authoring surface. Each owns a single concern; route work to the right one.
| Skill | Owns | Use for |
|---|---|---|
| powerbi-report-authoring | Report content (PBIR JSON authoring) | Pages, visuals, filters, formatting, themes, expressions, definition.pbir, version.json, report.json |
| powerbi-report-management (this skill) | Report transport to/from Fabric | List, create, get, update, delete report items; download/upload PBIR definitions |
| Semantic-model authoring skill | Semantic model authoring + deployment | Create/edit measures/tables/relationships, TMDL, deploy semantic models to Fabric |
When publishing a local .pbip to Fabric, this skill is the entry
point. If the user wants to publish the local semantic model alongside
the report, this skill delegates the model deploy to
an available semantic-model authoring skill, then resolves
the resulting semanticModelId and binds the report to it. See the
Publishing a local .pbip workflow.
| Tool | Role | Install |
|---|---|---|
| az CLI | Primary: az rest for Fabric REST API calls, az login for auth | Pre-installed in most dev environments |
| jq | Parse and construct JSON payloads | Standard CLI tool — see COMMON-CLI.md § Tool Selection Rationale |
| base64 | Encode/decode PBIR file content for definition payloads | Built-in on Linux/macOS · Windows: use PowerShell [Convert]::ToBase64String() / FromBase64String() |
Agent check — verify before first operation:
az version 2>/dev/null || echo "INSTALL: https://learn.microsoft.com/cli/azure/install-azure-cli"
All calls use the Fabric API audience. Using the wrong audience returns a 401.
| API | Audience (--resource) |
|---|---|
| Fabric Report Items API | https://api.fabric.microsoft.com |
For the shared authentication model, token audiences, and identity types, see COMMON-CORE.md § Authentication & Token Acquisition.
For full authentication recipes (interactive, device-code, service principal, managed identity), see COMMON-CLI.md § Authentication Recipes.
Shared patterns — workspace and item resolution, pagination, and LRO polling are documented in the common skill library. Read COMMON-CLI.md § Finding Workspaces and Items in Fabric before using the CRUD operations below.
Once you have the workspace ID (per COMMON-CLI.md), resolve the report:
REPORT_NAME="Sales Report"
REPORT_ID=$(az rest --method get \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports" \
--query "value[?displayName=='$REPORT_NAME'] | [0].id" \
--output tsv)
Returns all reports in a workspace.
Workspace.Read.All or Workspace.ReadWrite.Allaz rest --method get \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports" \
--query "value[].{name:displayName, id:id, description:description}" \
--output table
Supports pagination via continuationToken query parameter.
Returns properties of a specific report (name, description, ID, workspace, sensitivity label).
Report.Read.All or Report.ReadWrite.Allaz rest --method get \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports/$REPORT_ID"
Downloads the full PBIR definition. This is a POST (not GET) and supports LRO.
Report.ReadWrite.All or Item.ReadWrite.AllAlways request format=PBIR — without this parameter, older reports may
return PBIR-Legacy format (a single report.json blob), which this skill does
not support.
RESPONSE=$(az rest --method post \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports/$REPORT_ID/getDefinition?format=PBIR" \
--verbose 2>&1)
# If 202 Accepted, extract operation ID and poll the LRO (see Long-Running Operations section)
# If 200 OK, the response contains the definition parts
Format check: After retrieving the definition, verify
definition.format == "PBIR". If it is"PBIR-Legacy", this skill does not support that format.
Note:
getDefinitionoften returns202 Accepted(LRO). Check the Long-Running Operations section to extract the operation ID and poll for the result before decoding.
# After retrieving the definition (from 200 response or LRO result):
echo "$DEFINITION_JSON" | jq -r '.definition.parts[] | "\(.path)\t\(.payload)"' | \
while IFS=$'\t' read -r path payload; do
mkdir -p "$(dirname "./report-definition/$path")"
echo "$payload" | base64 -d > "./report-definition/$path"
done
Creates a new report with a PBIR definition. Supports LRO.
Report.ReadWrite.All or Item.ReadWrite.All# Walk ./report-definition/ and build the parts[] array — every file under the
# directory is encoded and uploaded. Includes definition.pbir, report.json,
# version.json, pages/pages.json, every pages/<page>/page.json, and every
# pages/<page>/visuals/<visual>/visual.json.
PARTS=$(find ./report-definition -type f -not -name '.*' -not -name 'Thumbs.db' | while read -r file; do
rel="${file#./report-definition/}"
payload=$(base64 < "$file" | tr -d '\n')
jq -nc --arg p "$rel" --arg b "$payload" \
'{path:$p, payload:$b, payloadType:"InlineBase64"}'
done | jq -sc '.')
jq -n \
--arg name "My New Report" \
--arg desc "Created via Fabric API" \
--argjson parts "$PARTS" \
'{displayName:$name, description:$desc, definition:{parts:$parts}}' \
> create-report.json
az rest --method post \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports" \
--headers "Content-Type=application/json" \
--body @create-report.json \
--verbose 2>&1
PowerShell — use
Get-ChildItem -Recurse -Fileto walk the directory and[Convert]::ToBase64String([System.IO.File]::ReadAllBytes($_.FullName))to encode each file (instead ofbase64 | tr -d '\n').
Important:
definition.pbiris always required. The directory walk above includes every file under./report-definition/automatically — make sure your local directory mirrors the full PBIR layout (top-level files, plus allpages/<page>/page.jsonandpages/<page>/visuals/<visual>/visual.jsonfiles) before encoding.
Overwrites the entire definition. This is a POST and supports LRO.
Report.ReadWrite.All or Item.ReadWrite.All# Rebuild parts[] from ./report-definition/ after edits (same walk as Create).
PARTS=$(find ./report-definition -type f -not -name '.*' -not -name 'Thumbs.db' | while read -r file; do
rel="${file#./report-definition/}"
payload=$(base64 < "$file" | tr -d '\n')
jq -nc --arg p "$rel" --arg b "$payload" \
'{path:$p, payload:$b, payloadType:"InlineBase64"}'
done | jq -sc '.')
jq -n --argjson parts "$PARTS" \
'{definition:{parts:$parts}}' \
> update-definition.json
az rest --method post \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports/$REPORT_ID/updateDefinition" \
--headers "Content-Type=application/json" \
--body @update-definition.json \
--verbose 2>&1
Critical:
updateDefinitionreplaces the entire definition. Include ALL parts — modified and unmodified. Omitting parts deletes them.
Optional query parameter ?updateMetadata=true updates item metadata from
.platform file if included.
Updates display name and/or description only (not the definition).
Report.ReadWrite.All or Item.ReadWrite.Allcat > update-report.json << 'EOF'
{
"displayName": "Renamed Report",
"description": "Updated description"
}
EOF
az rest --method patch \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports/$REPORT_ID" \
--headers "Content-Type=application/json" \
--body @update-report.json
Deletes a report. Supports soft-delete (default) and hard-delete.
Report.ReadWrite.All or Item.ReadWrite.All# Soft delete (recoverable)
az rest --method delete \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports/$REPORT_ID"
# Hard delete (permanent)
az rest --method delete \
--resource "https://api.fabric.microsoft.com" \
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/reports/$REPORT_ID?hardDelete=true"
Create Report, Get Report Definition, and Update Report Definition may
return 202 Accepted instead of an immediate result. Capture
x-ms-operation-id from the verbose output and poll until terminal state per
COMMON-CLI.md § Long-Running Operations.
The management-specific guardrails below take precedence over the generic pattern when they conflict.
⚠️ Never retry a create POST after receiving 202. A
202 Acceptedresponse means the operation was accepted and is likely being processed server-side. Retrying the POST risks creating duplicates.Always write
--verboseoutput to a file to reliably capture thex-ms-operation-idheader on every attempt — this is the only reliable way to track the operation. Regex extraction from in-memory strings is fragile across shells and platforms. Once captured, poll the operation to completion just like any other LRO call.# PowerShell — reliable operation ID capture az rest --method post ... --verbose 2>&1 | Out-File "$env:TEMP\lro-response.txt" -Encoding utf8 $opId = (Select-String -Path "$env:TEMP\lro-response.txt" -Pattern "x-ms-operation-id.*?'([a-f0-9-]+)'" | Select-Object -First 1).Matches.Groups[1].ValueAs a last resort, if the operation ID is still lost despite writing to a file, list reports in the workspace to locate the created report — but this should not be the normal path.
For more details, see Long-Running Operations.
Reports use the PBIR format — a folder of JSON files:
Report/
├── definition.pbir # Semantic model reference (required)
├── definition/
│ ├── report.json # Report-level settings (required)
│ ├── version.json # Format version (required)
│ ├── pages/
│ │ ├── pages.json # Page listing (required)
│ │ ├── <pageId>/
│ │ │ ├── page.json # Page layout
│ │ │ ├── visuals/
│ │ │ │ ├── <visualId>/
│ │ │ │ │ ├── visual.json # Visual config
│ │ │ │ │ ├── mobile.json # Mobile layout (optional)
│ ├── bookmarks/ # Bookmarks (optional)
├── StaticResources/ # Custom themes, images (optional)
All parts are base64-encoded in API payloads using "payloadType": "InlineBase64".
For Fabric API, use byConnection (not byPath):
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definitionProperties/2.0.0/schema.json",
"version": "4.0",
"datasetReference": {
"byConnection": {
"connectionString": "semanticmodelid=<SemanticModelId>"
}
}
}
powerbi-report-authoring skill — this is the single most important rule. Whether creating a brand-new report or modifying an existing one, every PBIR file (definition.pbir, report.json, version.json, pages.json, page configs, visuals, filters, formatting, themes, expressions) must be authored using powerbi-report-authoring. Follow its guidance for correct PBIR structure, schemas, and field values. Use its CLI tools for validation. Never construct any PBIR JSON from memory or guesswork — not even "simple" files like definition.pbir or version.json. This skill is strictly for API transport (download, encode, upload) — it does not author PBIR content.--resource "https://api.fabric.microsoft.com" to az rest — omitting it causes silent auth failures.?format=PBIR on getDefinition — without it, older reports return PBIR-Legacy format which is not supported by this skill."format": "PBIR-Legacy", stop and tell the user that PBIR-Legacy is not supported.updateDefinition — modified + unmodified. The API replaces the entire definition; omitting parts deletes them.payload value must be base64-encoded.byConnection in definition.pbir for Fabric API — byPath is for local/Git scenarios only.Create, getDefinition, and updateDefinition return 202 Accepted. Poll until terminal state.--verbose on LRO operations — az rest does not expose response headers by default. Without --verbose, you cannot capture the x-ms-operation-id header needed for polling, and there is no other way to retrieve it after the fact.Entity, queryRef, nativeQueryRef, filter Source/Entity references) against the model's table/column/measure names. This applies to both branches: even a hand-off deploy may rename or transform the model during publish, so the diff is not optional. If names differ but models are structurally equivalent (same columns/measures), remap all table-qualified bindings via powerbi-report-authoring. If the models are not structurally equivalent, prompt the user before attempting to re-author — explain which tables/columns/measures don't match and ask whether to proceed..pbip report, apply the changes to the local files only. Do not publish to Fabric unless the user explicitly asks to publish, upload, or push the report. Even if the report was previously published to Fabric, treat subsequent edits as local-only until told otherwise. When the user does request publishing a local .pbip, follow the Publishing a local .pbip workflow: (a) confirm the target workspace once up front, (b) prompt publish-the-local-model vs. connect-to-an-existing-workspace-model, (c) on the publish-model branch, check whether a semantic-model authoring skill is available in the current session and degrade gracefully if not, (d) confirm create-new vs. update-existing for the report itself.az rest with JMESPath --query for filtering — built-in JSON parsing, no extra tools needed.definition.pbir, report.json, version.json, pages, visuals, filters, formatting, themes, expressions) must go through the powerbi-report-authoring skill. Never construct any PBIR JSON from memory or guesswork — not even "simple" structural files. No exceptions.updateDefinition — the API replaces the full definition; missing parts are deleted.byPath in definition.pbir for API payloads — only works for local/Git scenarios.?format=PBIR on getDefinition — may return unusable PBIR-Legacy format..pbipThis is the primary entry point when a user has a local .pbip (report
plus sibling .SemanticModel) on disk and asks to publish, upload, push,
or deploy the report to a Fabric workspace.
1. Detect that the source is a local .pbip. Any of these signals:
<Name>.pbip file in or above the working directory.<Name>.Report folder with a sibling <Name>.SemanticModel folder.definition.pbir uses byPath (local/Git form) rather
than byConnection (API form)..pbi/ cache folder.If the source is not a local .pbip (e.g., the report was already
downloaded from Fabric and only the .Report folder is present with a
byConnection definition.pbir), use the
Modifying an existing report in Fabric
workflow instead.
2. Confirm the target workspace once. Resolve and store the workspace ID by name (per COMMON-CLI.md). This single workspace is reused for both the model deploy (if applicable) and the report publish — never split them.
3. Prompt the user about the semantic model. Ask explicitly — do not silently choose:
"Do you want me to publish the local semantic model to this workspace too, or connect this report to an existing semantic model already in the workspace?"
4a. Branch: "Publish the local model".
.SemanticModel folder path (TMDL source), and the
desired model display name. Wait for that skill's workflow to
reach terminal success before proceeding.4b. Branch: "Connect to an existing model in the workspace".
semanticModelId by name.5. Resolve semanticModelId. Regardless of branch, the report needs
a concrete model ID to bind to:
6. Verify bindings against the resolved model (universal, both
branches). Download the model TMDL and run the bindings diff per
MUST Verify semantic-model bindings after the target model is
resolved. Even on the publish-the-local-model branch, the
model skill may rename tables or apply transforms during deploy, so
this diff is not optional. Remap any drift via powerbi-report-authoring skill
or, if structurally divergent, prompt the user before re-authoring.
7. Rebind definition.pbir from byPath → byConnection. Use
powerbi-report-authoring to set:
"datasetReference": {
"byConnection": {
"connectionString": "semanticmodelid=<resolved-id>"
}
}
The Fabric API rejects byPath; this swap is mandatory on every
local-source publish.
8. Decide create-new vs. update-existing for the report. Default the
report displayName to the .pbip filename without extension (e.g.
SalesDashboard.pbip → "SalesDashboard"). Surface the default to the
user so they can override.
displayName.
updateDefinition), publish under a different name, or cancel.
Follow Update Report Definition on
overwrite.9. Encode and upload. Run the existing transport — base64-encode all
PBIR parts (forward-slash paths!), build the parts payload, POST,
capture x-ms-operation-id (with --verbose written to a file), poll
the LRO to terminal success.
10. Clean up any temporary files created during the flow.
Note on report-side verification: there is no reliable programmatic way to confirm a report renders correctly post-publish — the report lives at a Fabric Service URL and visual rendering requires a browser session. Surface the workspace/report URL so the user can verify in the browser.
getDefinition?format=PBIR → poll LRO → decode parts to local filespowerbi-report-authoring skill for ALL changes. This covers every file: definition.pbir, report.json, version.json, pages.json, page configs, visuals, filters, formatting, themes, and expressions. Follow its guidance for correct structure, schemas, and field values. Use its CLI tools to validate. Never construct any PBIR JSON from memory or guesswork.updateDefinition with ALL parts (modified + unmodified)definition.pbir connection stringEntity, queryRef, nativeQueryRef, and filter references against the target table/column names. If names differ but structure matches, remap all table-qualified bindings. If models are structurally different, prompt the user before proceeding — explain what doesn't match and ask whether to re-author the affected bindingspowerbi-report-authoring skill to generate the complete PBIR definition from scratch — definition.pbir, report.json, version.json, pages.json, page configs, and all visuals. Never construct any PBIR JSON from memory or guesswork.POST /reports with displayName and all definition parts| Error | Cause | Fix |
|---|---|---|
| 401 Unauthorized | Wrong or missing --resource audience | Always pass --resource "https://api.fabric.microsoft.com" |
| 403 Forbidden | Insufficient permissions | Check workspace role (Contributor+ for write ops) |
| 404 Not Found | Wrong workspace or report ID | Re-resolve IDs via List APIs |
| CorruptedPayload | Malformed base64 or invalid PBIR JSON | Re-encode files; validate JSON before encoding |
| 202 with no result | LRO not polled to completion | Implement LRO polling pattern |
| OperationNotSupportedForItem | Report has encrypted sensitivity label | Cannot get definition for encrypted reports |
| ItemDisplayNameAlreadyInUse | Duplicate name in workspace | Use a unique display name |
| format: "PBIR-Legacy" | Report was created before PBIR was default | PBIR-Legacy is not supported by this skill |
| Visuals empty / no data after publish | PBIR entity names don't match workspace semantic model table names (e.g., local CSV table name vs workspace table name) | Download target semantic model TMDL, compare table names, update all Entity, queryRef, nativeQueryRef, and filter references to match |
| MissingDefinitionParts on create/update even though all files are included | Definition part paths use backslashes (definition\report.json) — the Fabric API requires forward slashes. On Windows, path.join() produces backslashes by default. | Normalize all path values in the payload to use forward slashes before uploading (e.g., .replace(/\\\\/g, '/') in Node.js, or .Replace('\\', '/') in PowerShell). |
| Duplicate reports appear in workspace after create | Create POST was retried after a 202 Accepted response. Each retry risks creating a new report. | Never retry a create POST after 202. See the LRO section for reliable operation ID capture and recovery steps. Delete any duplicates with the Delete Report API. |
| Visuals empty after publishing a local .pbip via the model hand-off | The semantic-model authoring skill may rename or transform tables/columns during deploy, so the freshly deployed model's TMDL no longer matches the report's PBIR bindings. | Re-run the TMDL-diff verification against the deployed model (per MUST Verify semantic-model bindings after the target model is resolved) and remap drifted bindings via powerbi-report-authoring skill. |
| Visuals empty after publish, despite TMDL diff being clean | definition.pbir byConnection still points at a stale model ID (e.g., from .pbi/ cache or an earlier publish), not the freshly resolved one. | Re-run step 7 of Publishing a local .pbip to set byConnection to the actually resolved semanticModelId, then re-publish. |
| Semantic-model authoring skill not available when user wants to publish the local model | No semantic-model authoring skill is loaded in the current session. | Inform the user and degrade to the connect-to-existing branch — re-prompt for which workspace model to bind the report to. Do not silently fall through. |
| Model published to one workspace, report POSTed to another | Workspace was not confirmed up front, or two different workspaces were used for the model deploy and the report publish. | Enforce the single-workspace rule (step 2 of Publishing a local .pbip). Recovery: either re-publish the report into the model's workspace, or move the model. |
development
Build a guided requirements-to-implementation workflow for new Power BI reports and dashboards from semantic models, datasets, or PBIP projects. Use when the user wants to: (1) plan then implement a report, (2) define audience, scope, page plan, design direction, dependencies, and delivery target, (3) create a locked report spec with approval before PBIR authoring. For direct edits to existing report files, use `powerbi-report-authoring`. For design-only critique or redesign, use `powerbi-report-design`. Triggers: "build me a dashboard", "create a new report", "plan then implement", "define and build Power BI report", "walk me through creating a report".
development
Generate Power BI report visual design guidance before PBIR files are written. Use when the user wants to: (1) choose tone, signature, page archetypes, chart types, layout, color, typography, theme direction, or accessibility approach, (2) redesign/restyle an existing report, apply a brand, or critique chart/layout choices, (3) produce a design contract for `powerbi-report-authoring`. For end-to-end requirements, approval, and build sequencing, use `powerbi-report-planning`. Triggers: "design Power BI report", "make dashboard look professional", "choose chart type", "apply brand to report", "redesign report", "create design brief".
tools
Create and modify Power BI report files in PBIR/PBIP format using the `powerbi-report-author` and `powerbi-desktop` CLIs. Use when the user wants to: (1) implement an approved report spec or design brief, (2) add or edit pages, visuals, filters, slicers, bookmarks, themes, or formatting, (3) validate PBIR and verify rendering in Power BI Desktop. For open-ended visual design, use `powerbi-report-design` first. For end-to-end requirements and approval workflow, use `powerbi-report-planning` first. Triggers: "edit PBIR", "create Power BI report page", "add visual to PBIP", "format report visual", "validate Power BI report", "reload Desktop screenshot", "implement an approved PBIP report spec", "edit PBIR pages/visuals".
development
Build a guided requirements-to-implementation workflow for new Power BI reports and dashboards from semantic models, datasets, or PBIP projects. Use when the user wants to: (1) plan then implement a report, (2) define audience, scope, page plan, design direction, dependencies, and delivery target, (3) create a locked report spec with approval before PBIR authoring. For direct edits to existing report files, use `powerbi-report-authoring`. For design-only critique or redesign, use `powerbi-report-design`. Triggers: "build me a dashboard", "create a new report", "plan then implement", "define and build Power BI report", "walk me through creating a report".