Power BI has no single CLI. Three tools cover the CI, authoring, and comparison roles.
| Tool | Role | Distributed as |
|---|---|---|
| Tabular Editor CLI | BPA validation, TMDL manipulation, XMLA deploys | Windows .exe, cross-platform via .NET |
| ALM Toolkit CLI | Model diff, selective deployment | Windows .exe; partial CLI |
| fabric-cicd | Deploy PBIP artifacts to Fabric workspaces | Python package |
Tabular Editor CLI
Tabular Editor 3 ships a command-line mode that runs scripts, BPA rules, and XMLA operations. The binary is called TabularEditor.exe on Windows; a .NET build runs on Linux and macOS.
Run BPA rules
./TabularEditor.exe `
./sales_model.SemanticModel `
-A "./BPA Rules.json" `
-V
-A <file>loads a BPA rule file and runs it against the model.-Vfails the process with a non-zero exit code if any error-level rule is violated.
Exit code is 0 on success, non-zero on BPA failures or model errors. Use in CI as a gate.
Run a script
./TabularEditor.exe `
./sales_model.SemanticModel `
-S "./scripts/add_yoy_measures.csx"
-S <file>runs a C# script against the model. Script changes are persisted unless you add-P false.
Scripts are the idiomatic way to make structural changes to a shared semantic model:
// add_yoy_measures.csx
foreach (var m in Model.AllMeasures.Where(m => m.Name.StartsWith("Total "))) {
var yoy = m.Table.AddMeasure(m.Name.Replace("Total ", "") + " YoY");
yoy.Expression = $@"
VAR Current = [{m.Name}]
VAR Prior = CALCULATE([{m.Name}], SAMEPERIODLASTYEAR('dim_date'[date]))
RETURN DIVIDE(Current - Prior, Prior)
";
yoy.FormatString = "0.00%;-0.00%;0%";
}
XMLA deploy
./TabularEditor.exe `
./sales_model.SemanticModel `
-D "powerbi://api.powerbi.com/v1.0/myorg/workspace-dev" "sales_model" `
-O "Preserve=false"
-D <endpoint> <database>deploys to an XMLA endpoint.-Osets deployment options.
Prefer fabric-cicd for routine deploys; reach for Tabular Editor's -D for one-off surgical deploys.
Help
./TabularEditor.exe -h
Full option list. Read it once; come back when you need a flag.
fabric-cicd
Microsoft-published Python package for deploying PBIP artifacts to Fabric workspaces.
Install
pip install fabric-cicd
Validate
fabric-cicd validate --config config.yml
Checks that the PBIP folder structure is correct, workspace IDs in config exist, and environment parameters substitute cleanly.
Deploy
fabric-cicd deploy --target dev --config config.yml
fabric-cicd deploy --target staging --config config.yml
fabric-cicd deploy --target prod --config config.yml
Deploys semantic models and reports to the named target's workspace. Auth via the Azure CLI's active context (typically OIDC from CI).
Config
The config defines workspaces, items (models, reports), and per-target parameters:
workspaces:
dev: { id: "00000000-0000-0000-0000-000000000001" }
staging: { id: "00000000-0000-0000-0000-000000000002" }
prod: { id: "00000000-0000-0000-0000-000000000003" }
items:
- name: sales_model
type: SemanticModel
path: ./sales_model.SemanticModel
- name: sales_report
type: Report
path: ./sales_report.Report
environment_parameters:
dev:
- name: warehouse_id
value: "abc123"
prod:
- name: warehouse_id
value: "ghi789"
See the CI/CD guide for the full pipeline.
ALM Toolkit CLI
Compares two tabular models, generates selective deployment scripts.
Compare two models
./AlmToolkit.exe compare `
--source "Data Source=powerbi://api.powerbi.com/v1.0/myorg/staging;Initial Catalog=sales_model" `
--target "Data Source=powerbi://api.powerbi.com/v1.0/myorg/prod;Initial Catalog=sales_model" `
--output diff.txt
Produces a diff of every object (tables, measures, relationships, roles) between source and target.
Selective deploy
./AlmToolkit.exe deploy `
--source ... --target ... `
--select "measure:Total Revenue"
Deploys only the named object, preserving the rest.
Use for surgical prod fixes: a single measure definition needs to change, you do not want a full model redeploy, and you do not want to lose parallel PRs that have been merged since the last deploy.
Warning
ALM Toolkit's selective deploy is a surgical tool. Use it for measures and calculated expressions. Avoid it for structural changes (relationships, new tables) where the side effects are larger and a full fabric-cicd deploy is safer.
Power BI REST API via curl
When you need a thing neither tool exposes, hit the REST API directly.
Auth: get a bearer token
TOKEN=$(curl -s -X POST \
"https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "scope=https://analysis.windows.net/powerbi/api/.default" \
| jq -r '.access_token')
List workspaces
curl -s "https://api.powerbi.com/v1.0/myorg/groups" \
-H "Authorization: Bearer $TOKEN" | jq '.value[] | {id, name}'
List datasets in a workspace
curl -s "https://api.powerbi.com/v1.0/myorg/groups/$WORKSPACE_ID/datasets" \
-H "Authorization: Bearer $TOKEN" | jq '.value[] | {id, name, configuredBy}'
Trigger refresh
curl -s -X POST \
"https://api.powerbi.com/v1.0/myorg/groups/$WORKSPACE_ID/datasets/$DATASET_ID/refreshes" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": "full", "commitMode": "transactional"}'
Refresh history
curl -s "https://api.powerbi.com/v1.0/myorg/groups/$WORKSPACE_ID/datasets/$DATASET_ID/refreshes" \
-H "Authorization: Bearer $TOKEN" | jq '.value[] | {status, startTime, endTime}'
When to use which tool
| Task | Tool |
|---|---|
| CI deploy of PBIP to a workspace | fabric-cicd |
| BPA validation in CI | Tabular Editor CLI |
| Scripted model edits (bulk add, refactor) | Tabular Editor CLI |
| Compare two models, see what differs | ALM Toolkit CLI |
| Deploy one measure without redeploying everything | ALM Toolkit CLI |
| Trigger a refresh, query refresh history | REST API (curl/Python) |
| List/enumerate workspaces, datasets | REST API |
See also
- CI/CD for Power BI — fabric-cicd in context.
- Enhanced Refresh — what the REST API refresh endpoint looks like in production.
- PBIP + Git — the source format these tools consume.