From 7eff3423a97a60e5f6253bc60ab17a08a9ce07d8 Mon Sep 17 00:00:00 2001 From: may-hartov Date: Mon, 16 Feb 2026 10:41:04 +0200 Subject: [PATCH 1/4] create sample of dataset refresh using API command --- .changes/unreleased/docs-20260216-084028.yaml | 6 + docs/examples/item_examples.md | 6 +- docs/examples/refresh_dataset_example.md | 258 ++++++++++++++++++ mkdocs.yml | 1 + 4 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/docs-20260216-084028.yaml create mode 100644 docs/examples/refresh_dataset_example.md diff --git a/.changes/unreleased/docs-20260216-084028.yaml b/.changes/unreleased/docs-20260216-084028.yaml new file mode 100644 index 00000000..f61e9a90 --- /dev/null +++ b/.changes/unreleased/docs-20260216-084028.yaml @@ -0,0 +1,6 @@ +kind: docs +body: Created refresh dataset using API command example +time: 2026-02-16T08:40:28.503495133Z +custom: + Author: may-hartov + AuthorLink: https://github.com/may-hartov diff --git a/docs/examples/item_examples.md b/docs/examples/item_examples.md index 48ab6c96..cab63c85 100644 --- a/docs/examples/item_examples.md +++ b/docs/examples/item_examples.md @@ -380,9 +380,13 @@ fab stop ws1.Workspace/mir1.MirroredDatabase Stop mirrored database without confirmation. ``` -fab stop ws1.Workspacemir1.MirroredDatabase -f +fab stop ws1.Workspace/mir1.MirroredDatabase -f ``` +### Dataset Refresh + +For detailed examples on triggering and monitoring semantic model (dataset) refresh operations using the API command, see the [Dataset Refresh Example](refresh_dataset_example.md). + ### Open in Browser #### Open Item in Web Interface diff --git a/docs/examples/refresh_dataset_example.md b/docs/examples/refresh_dataset_example.md new file mode 100644 index 00000000..4245fb94 --- /dev/null +++ b/docs/examples/refresh_dataset_example.md @@ -0,0 +1,258 @@ +# Dataset Refresh Using API Command + +This guide shows how to trigger and monitor Power BI semantic model (dataset) refresh using the Fabric CLI `api` command with polling implementation. + +## APIs Used + +This script demonstrates two Power BI REST API endpoints: + +### Refresh Dataset In Group + +**[Refresh Dataset In Group](https://learn.microsoft.com/rest/api/power-bi/datasets/refresh-dataset-in-group)** - Triggers an on-demand dataset refresh operation + +- Method: `POST` +- Endpoint: `groups/{workspaceId}/datasets/{datasetId}/refreshes` + +### Get Refresh Execution Details In Group + +**[Get Refresh Execution Details In Group](https://learn.microsoft.com/rest/api/power-bi/datasets/get-refresh-execution-details-in-group)** - Retrieves the status of a specific refresh operation + +- Method: `GET` +- Endpoint: `groups/{workspaceId}/datasets/{datasetId}/refreshes/{refreshId}` + +The POST response includes a `Location` header containing the polling URL, or a `RequestId` header that can be used to construct the polling endpoint for the GET request. + +## Script Examples + +This script triggers a dataset refresh, extracts the polling endpoint from the response headers, and continuously polls the refresh status until it completes (successfully or with an error). + +Replace the following placeholders before running: + +- **`{WORKSPACE_ID}`** - Your workspace ID +- **`{DATASET_ID}`** - Your dataset ID +- **`{POLLING_INTERVAL}`** - Polling interval in seconds + +=== "PowerShell" + ```powershell + # Configuration + $WorkspaceId = "{WORKSPACE_ID}" + $DatasetId = "{DATASET_ID}" + $PollingInterval = {POLLING_INTERVAL} # seconds + + # Step 1: Trigger refresh with Transactional commit mode + Write-Host "Triggering dataset refresh..." -ForegroundColor Cyan + + # Customize the request body according to your needs + # See: https://learn.microsoft.com/en-us/rest/api/power-bi/datasets/refresh-dataset-in-group#request-body + # Note: The -i flag uses nargs="+", so the JSON must be passed as a single quoted string with escaped quotes + $requestBody = '{\"retryCount\":\"1\",\"timeout\":\"00:20:00\"}' + + $refreshResponse = fab api -A powerbi -X post "groups/$WorkspaceId/datasets/$DatasetId/refreshes" --show_headers -i $requestBody + + # Parse the response as JSON and check status code + try { + $refreshJson = $refreshResponse | ConvertFrom-Json + $statusCode = $refreshJson.status_code + + # Check POST response status (expecting 202 Accepted) + if ($statusCode -ne 202) { + Write-Host "Error: Expected status code 202, but received $statusCode" -ForegroundColor Red + Write-Host "Response:" -ForegroundColor Yellow + Write-Host $refreshResponse + exit 1 + } + } catch { + Write-Host "Warning: Could not parse response as JSON" -ForegroundColor Yellow + Write-Host "Response: $refreshResponse" -ForegroundColor Gray + } + + # Step 2: Extract polling URL from Location header or build from RequestId + $pollingEndpoint = $null + + # Try to extract Location header first (preferred method) + if ($refreshJson.headers.Location) { + $locationUrl = $refreshJson.headers.Location + if ($locationUrl -match 'https?://[^/]+/v1\.0/myorg/(.+)') { + $pollingEndpoint = $Matches[1].Trim() + } + } + + # Fallback to RequestId header if Location not present + if (-not $pollingEndpoint) { + if ($refreshJson.headers.RequestId) { + $refreshId = $refreshJson.headers.RequestId + # Build the polling endpoint manually + $pollingEndpoint = "groups/$WorkspaceId/datasets/$DatasetId/refreshes/$refreshId" + } + } + + if (-not $pollingEndpoint) { + Write-Host "Error: Could not extract polling endpoint from response headers" -ForegroundColor Red + exit 1 + } + + Write-Host "Polling endpoint: $pollingEndpoint`n" -ForegroundColor Cyan + + # Step 3: Poll for completion + $status = "" + + while ($true) { + Start-Sleep -Seconds $PollingInterval + + # Get refresh status using the polling endpoint + $statusResponse = fab api -A powerbi $pollingEndpoint --show_headers + + # Parse JSON response and check status code + try { + $statusResponseJson = $statusResponse | ConvertFrom-Json + $getStatusCode = $statusResponseJson.status_code + + # Check GET response status (expecting 200 or 202) + if ($getStatusCode -ne 200 -and $getStatusCode -ne 202) { + Write-Host " Warning: Expected status code 200 or 202, but received $getStatusCode" -ForegroundColor Yellow + Write-Host " Response:" -ForegroundColor Yellow + Write-Host $statusResponse + } + + # Extract the actual status from the response body (text field is already an object) + $statusJson = $statusResponseJson.text + + # Use extendedStatus if available, otherwise fallback to status + $status = if ($statusJson.extendedStatus) { $statusJson.extendedStatus } else { $statusJson.status } + + # Always print the status first + Write-Host " Refresh Status: $status" -ForegroundColor Cyan + + # Then handle completion states + switch -Regex ($status) { + "^Completed$" { + Write-Host "`nRefresh completed successfully" -ForegroundColor Green + exit 0 + } + "^(Failed|Cancelled|Disabled|TimedOut)$" { + Write-Host "`nRefresh failed" -ForegroundColor Red + Write-Host $statusResponse + exit 1 + } + "^(NotStarted|InProgress|Unknown)$" { + # Continue polling + } + default { + Write-Host "`nUnknown status encountered" -ForegroundColor Magenta + Write-Host $statusResponse + exit 1 + } + } + } catch { + Write-Host " Error parsing response: $_" -ForegroundColor Red + Write-Host " Raw response: $statusResponse" -ForegroundColor Gray + } + } + ``` + +=== "Bash" + ```bash + #!/bin/bash + + # Configuration + WORKSPACE_ID="{WORKSPACE_ID}" + DATASET_ID="{DATASET_ID}" + POLLING_INTERVAL={POLLING_INTERVAL} # seconds + + # Step 1: Trigger refresh with Transactional commit mode + echo -e "\033[0;36mTriggering dataset refresh...\033[0m" + + # Customize the request body according to your needs + # See: https://learn.microsoft.com/en-us/rest/api/power-bi/datasets/refresh-dataset-in-group#request-body + REQUEST_BODY='{"retryCount":"1","timeout":"00:20:00"}' + + REFRESH_RESPONSE=$(fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$DATASET_ID/refreshes" --show_headers -i "$REQUEST_BODY") + + # Parse the response as JSON and check status code + STATUS_CODE=$(echo "$REFRESH_RESPONSE" | jq -r '.status_code // empty') + + # Check POST response status (expecting 202 Accepted) + if [ "$STATUS_CODE" != "202" ]; then + echo -e "\033[0;31mError: Expected status code 202, but received $STATUS_CODE\033[0m" + echo -e "\033[0;33mResponse:\033[0m" + echo "$REFRESH_RESPONSE" + exit 1 + fi + + # Step 2: Extract polling URL from Location header or build from RequestId + POLLING_ENDPOINT="" + + # Try to extract Location header first (preferred method) + LOCATION=$(echo "$REFRESH_RESPONSE" | jq -r '.headers.Location // empty') + if [ -n "$LOCATION" ]; then + # Extract the endpoint path after /v1.0/myorg/ + POLLING_ENDPOINT=$(echo "$LOCATION" | sed -n 's|.*https\?://[^/]*/v1\.0/myorg/\(.*\)|\1|p' | xargs) + fi + + # Fallback to RequestId header if Location not present + if [ -z "$POLLING_ENDPOINT" ]; then + REQUEST_ID=$(echo "$REFRESH_RESPONSE" | jq -r '.headers.RequestId // empty') + if [ -n "$REQUEST_ID" ]; then + # Build the polling endpoint manually + POLLING_ENDPOINT="groups/$WORKSPACE_ID/datasets/$DATASET_ID/refreshes/$REQUEST_ID" + fi + fi + + if [ -z "$POLLING_ENDPOINT" ]; then + echo -e "\033[0;31mError: Could not extract polling endpoint from response headers\033[0m" + exit 1 + fi + + echo -e "\033[0;36mPolling endpoint: $POLLING_ENDPOINT\033[0m\n" + + # Step 3: Poll for completion + while true; do + sleep "$POLLING_INTERVAL" + + # Get refresh status using the polling endpoint + STATUS_RESPONSE=$(fab api -A powerbi "$POLLING_ENDPOINT" --show_headers) + + # Parse JSON response and check status code + GET_STATUS_CODE=$(echo "$STATUS_RESPONSE" | jq -r '.status_code // empty') + + # Check GET response status (expecting 200 or 202) + if [ "$GET_STATUS_CODE" != "200" ] && [ "$GET_STATUS_CODE" != "202" ]; then + echo -e " \033[0;33mWarning: Expected status code 200 or 202, but received $GET_STATUS_CODE\033[0m" + echo -e " \033[0;33mResponse:\033[0m" + echo "$STATUS_RESPONSE" + fi + + # Extract the actual status from the response body + # Use extendedStatus if available, otherwise fallback to status + EXTENDED_STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.text.extendedStatus // empty') + if [ -n "$EXTENDED_STATUS" ]; then + STATUS="$EXTENDED_STATUS" + else + STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.text.status // empty') + fi + + # Always print the status first + echo -e " \033[0;36mRefresh Status: $STATUS\033[0m" + + # Then handle completion states + case "$STATUS" in + "Completed") + echo -e "\n\033[0;32mRefresh completed successfully\033[0m" + exit 0 + ;; + "Failed"|"Cancelled"|"Disabled"|"TimedOut") + echo -e "\n\033[0;31mRefresh failed\033[0m" + echo "$STATUS_RESPONSE" + exit 1 + ;; + "NotStarted"|"InProgress"|"Unknown") + # Continue polling + ;; + *) + echo -e "\n\033[0;35mUnknown status encountered\033[0m" + echo "$STATUS_RESPONSE" + exit 1 + ;; + esac + done + ``` diff --git a/mkdocs.yml b/mkdocs.yml index 1dd38219..3e797107 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -123,6 +123,7 @@ nav: - Workspace Examples: examples/workspace_examples.md - Item Management: - Item Examples: examples/item_examples.md + - Dataset Refresh Example: examples/refresh_dataset_example.md - Job Examples: examples/job_examples.md - Label Examples: examples/label_examples.md - Data & Storage: From 7834bfbfe2602b09196fb21da3ff06e619bd79eb Mon Sep 17 00:00:00 2001 From: may-hartov Date: Tue, 17 Feb 2026 08:36:10 +0200 Subject: [PATCH 2/4] CR fixes --- docs/examples/api_examples.md | 6 +- docs/examples/item_examples.md | 4 +- docs/examples/refresh_dataset_example.md | 258 ------------------ .../refresh_semantic_model_example.md | 205 ++++++++++++++ mkdocs.yml | 5 +- 5 files changed, 215 insertions(+), 263 deletions(-) delete mode 100644 docs/examples/refresh_dataset_example.md create mode 100644 docs/examples/refresh_semantic_model_example.md diff --git a/docs/examples/api_examples.md b/docs/examples/api_examples.md index 2adbc90e..fa7d688b 100644 --- a/docs/examples/api_examples.md +++ b/docs/examples/api_examples.md @@ -109,4 +109,8 @@ Retrieve Power BI workspace details. ``` fab api -A powerbi groups/00000000-0000-0000-0000-000000000000 -``` \ No newline at end of file +``` + +### Refresh Semantic Model + +For detailed examples on triggering and monitoring semantic model refresh using the API command, see the [Semantic Model Refresh Example](refresh_semantic_model_example.md). \ No newline at end of file diff --git a/docs/examples/item_examples.md b/docs/examples/item_examples.md index cab63c85..9b1b280e 100644 --- a/docs/examples/item_examples.md +++ b/docs/examples/item_examples.md @@ -383,9 +383,9 @@ Stop mirrored database without confirmation. fab stop ws1.Workspace/mir1.MirroredDatabase -f ``` -### Dataset Refresh +### Semantic Model Refresh -For detailed examples on triggering and monitoring semantic model (dataset) refresh operations using the API command, see the [Dataset Refresh Example](refresh_dataset_example.md). +For detailed examples on triggering and monitoring semantic model refresh using the API command, see the [Semantic Model Refresh Example](refresh_semantic_model_example.md). ### Open in Browser diff --git a/docs/examples/refresh_dataset_example.md b/docs/examples/refresh_dataset_example.md deleted file mode 100644 index 4245fb94..00000000 --- a/docs/examples/refresh_dataset_example.md +++ /dev/null @@ -1,258 +0,0 @@ -# Dataset Refresh Using API Command - -This guide shows how to trigger and monitor Power BI semantic model (dataset) refresh using the Fabric CLI `api` command with polling implementation. - -## APIs Used - -This script demonstrates two Power BI REST API endpoints: - -### Refresh Dataset In Group - -**[Refresh Dataset In Group](https://learn.microsoft.com/rest/api/power-bi/datasets/refresh-dataset-in-group)** - Triggers an on-demand dataset refresh operation - -- Method: `POST` -- Endpoint: `groups/{workspaceId}/datasets/{datasetId}/refreshes` - -### Get Refresh Execution Details In Group - -**[Get Refresh Execution Details In Group](https://learn.microsoft.com/rest/api/power-bi/datasets/get-refresh-execution-details-in-group)** - Retrieves the status of a specific refresh operation - -- Method: `GET` -- Endpoint: `groups/{workspaceId}/datasets/{datasetId}/refreshes/{refreshId}` - -The POST response includes a `Location` header containing the polling URL, or a `RequestId` header that can be used to construct the polling endpoint for the GET request. - -## Script Examples - -This script triggers a dataset refresh, extracts the polling endpoint from the response headers, and continuously polls the refresh status until it completes (successfully or with an error). - -Replace the following placeholders before running: - -- **`{WORKSPACE_ID}`** - Your workspace ID -- **`{DATASET_ID}`** - Your dataset ID -- **`{POLLING_INTERVAL}`** - Polling interval in seconds - -=== "PowerShell" - ```powershell - # Configuration - $WorkspaceId = "{WORKSPACE_ID}" - $DatasetId = "{DATASET_ID}" - $PollingInterval = {POLLING_INTERVAL} # seconds - - # Step 1: Trigger refresh with Transactional commit mode - Write-Host "Triggering dataset refresh..." -ForegroundColor Cyan - - # Customize the request body according to your needs - # See: https://learn.microsoft.com/en-us/rest/api/power-bi/datasets/refresh-dataset-in-group#request-body - # Note: The -i flag uses nargs="+", so the JSON must be passed as a single quoted string with escaped quotes - $requestBody = '{\"retryCount\":\"1\",\"timeout\":\"00:20:00\"}' - - $refreshResponse = fab api -A powerbi -X post "groups/$WorkspaceId/datasets/$DatasetId/refreshes" --show_headers -i $requestBody - - # Parse the response as JSON and check status code - try { - $refreshJson = $refreshResponse | ConvertFrom-Json - $statusCode = $refreshJson.status_code - - # Check POST response status (expecting 202 Accepted) - if ($statusCode -ne 202) { - Write-Host "Error: Expected status code 202, but received $statusCode" -ForegroundColor Red - Write-Host "Response:" -ForegroundColor Yellow - Write-Host $refreshResponse - exit 1 - } - } catch { - Write-Host "Warning: Could not parse response as JSON" -ForegroundColor Yellow - Write-Host "Response: $refreshResponse" -ForegroundColor Gray - } - - # Step 2: Extract polling URL from Location header or build from RequestId - $pollingEndpoint = $null - - # Try to extract Location header first (preferred method) - if ($refreshJson.headers.Location) { - $locationUrl = $refreshJson.headers.Location - if ($locationUrl -match 'https?://[^/]+/v1\.0/myorg/(.+)') { - $pollingEndpoint = $Matches[1].Trim() - } - } - - # Fallback to RequestId header if Location not present - if (-not $pollingEndpoint) { - if ($refreshJson.headers.RequestId) { - $refreshId = $refreshJson.headers.RequestId - # Build the polling endpoint manually - $pollingEndpoint = "groups/$WorkspaceId/datasets/$DatasetId/refreshes/$refreshId" - } - } - - if (-not $pollingEndpoint) { - Write-Host "Error: Could not extract polling endpoint from response headers" -ForegroundColor Red - exit 1 - } - - Write-Host "Polling endpoint: $pollingEndpoint`n" -ForegroundColor Cyan - - # Step 3: Poll for completion - $status = "" - - while ($true) { - Start-Sleep -Seconds $PollingInterval - - # Get refresh status using the polling endpoint - $statusResponse = fab api -A powerbi $pollingEndpoint --show_headers - - # Parse JSON response and check status code - try { - $statusResponseJson = $statusResponse | ConvertFrom-Json - $getStatusCode = $statusResponseJson.status_code - - # Check GET response status (expecting 200 or 202) - if ($getStatusCode -ne 200 -and $getStatusCode -ne 202) { - Write-Host " Warning: Expected status code 200 or 202, but received $getStatusCode" -ForegroundColor Yellow - Write-Host " Response:" -ForegroundColor Yellow - Write-Host $statusResponse - } - - # Extract the actual status from the response body (text field is already an object) - $statusJson = $statusResponseJson.text - - # Use extendedStatus if available, otherwise fallback to status - $status = if ($statusJson.extendedStatus) { $statusJson.extendedStatus } else { $statusJson.status } - - # Always print the status first - Write-Host " Refresh Status: $status" -ForegroundColor Cyan - - # Then handle completion states - switch -Regex ($status) { - "^Completed$" { - Write-Host "`nRefresh completed successfully" -ForegroundColor Green - exit 0 - } - "^(Failed|Cancelled|Disabled|TimedOut)$" { - Write-Host "`nRefresh failed" -ForegroundColor Red - Write-Host $statusResponse - exit 1 - } - "^(NotStarted|InProgress|Unknown)$" { - # Continue polling - } - default { - Write-Host "`nUnknown status encountered" -ForegroundColor Magenta - Write-Host $statusResponse - exit 1 - } - } - } catch { - Write-Host " Error parsing response: $_" -ForegroundColor Red - Write-Host " Raw response: $statusResponse" -ForegroundColor Gray - } - } - ``` - -=== "Bash" - ```bash - #!/bin/bash - - # Configuration - WORKSPACE_ID="{WORKSPACE_ID}" - DATASET_ID="{DATASET_ID}" - POLLING_INTERVAL={POLLING_INTERVAL} # seconds - - # Step 1: Trigger refresh with Transactional commit mode - echo -e "\033[0;36mTriggering dataset refresh...\033[0m" - - # Customize the request body according to your needs - # See: https://learn.microsoft.com/en-us/rest/api/power-bi/datasets/refresh-dataset-in-group#request-body - REQUEST_BODY='{"retryCount":"1","timeout":"00:20:00"}' - - REFRESH_RESPONSE=$(fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$DATASET_ID/refreshes" --show_headers -i "$REQUEST_BODY") - - # Parse the response as JSON and check status code - STATUS_CODE=$(echo "$REFRESH_RESPONSE" | jq -r '.status_code // empty') - - # Check POST response status (expecting 202 Accepted) - if [ "$STATUS_CODE" != "202" ]; then - echo -e "\033[0;31mError: Expected status code 202, but received $STATUS_CODE\033[0m" - echo -e "\033[0;33mResponse:\033[0m" - echo "$REFRESH_RESPONSE" - exit 1 - fi - - # Step 2: Extract polling URL from Location header or build from RequestId - POLLING_ENDPOINT="" - - # Try to extract Location header first (preferred method) - LOCATION=$(echo "$REFRESH_RESPONSE" | jq -r '.headers.Location // empty') - if [ -n "$LOCATION" ]; then - # Extract the endpoint path after /v1.0/myorg/ - POLLING_ENDPOINT=$(echo "$LOCATION" | sed -n 's|.*https\?://[^/]*/v1\.0/myorg/\(.*\)|\1|p' | xargs) - fi - - # Fallback to RequestId header if Location not present - if [ -z "$POLLING_ENDPOINT" ]; then - REQUEST_ID=$(echo "$REFRESH_RESPONSE" | jq -r '.headers.RequestId // empty') - if [ -n "$REQUEST_ID" ]; then - # Build the polling endpoint manually - POLLING_ENDPOINT="groups/$WORKSPACE_ID/datasets/$DATASET_ID/refreshes/$REQUEST_ID" - fi - fi - - if [ -z "$POLLING_ENDPOINT" ]; then - echo -e "\033[0;31mError: Could not extract polling endpoint from response headers\033[0m" - exit 1 - fi - - echo -e "\033[0;36mPolling endpoint: $POLLING_ENDPOINT\033[0m\n" - - # Step 3: Poll for completion - while true; do - sleep "$POLLING_INTERVAL" - - # Get refresh status using the polling endpoint - STATUS_RESPONSE=$(fab api -A powerbi "$POLLING_ENDPOINT" --show_headers) - - # Parse JSON response and check status code - GET_STATUS_CODE=$(echo "$STATUS_RESPONSE" | jq -r '.status_code // empty') - - # Check GET response status (expecting 200 or 202) - if [ "$GET_STATUS_CODE" != "200" ] && [ "$GET_STATUS_CODE" != "202" ]; then - echo -e " \033[0;33mWarning: Expected status code 200 or 202, but received $GET_STATUS_CODE\033[0m" - echo -e " \033[0;33mResponse:\033[0m" - echo "$STATUS_RESPONSE" - fi - - # Extract the actual status from the response body - # Use extendedStatus if available, otherwise fallback to status - EXTENDED_STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.text.extendedStatus // empty') - if [ -n "$EXTENDED_STATUS" ]; then - STATUS="$EXTENDED_STATUS" - else - STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.text.status // empty') - fi - - # Always print the status first - echo -e " \033[0;36mRefresh Status: $STATUS\033[0m" - - # Then handle completion states - case "$STATUS" in - "Completed") - echo -e "\n\033[0;32mRefresh completed successfully\033[0m" - exit 0 - ;; - "Failed"|"Cancelled"|"Disabled"|"TimedOut") - echo -e "\n\033[0;31mRefresh failed\033[0m" - echo "$STATUS_RESPONSE" - exit 1 - ;; - "NotStarted"|"InProgress"|"Unknown") - # Continue polling - ;; - *) - echo -e "\n\033[0;35mUnknown status encountered\033[0m" - echo "$STATUS_RESPONSE" - exit 1 - ;; - esac - done - ``` diff --git a/docs/examples/refresh_semantic_model_example.md b/docs/examples/refresh_semantic_model_example.md new file mode 100644 index 00000000..a120019c --- /dev/null +++ b/docs/examples/refresh_semantic_model_example.md @@ -0,0 +1,205 @@ +# Semantic Model Refresh + +This guide shows how to trigger and monitor Power BI semantic model refresh using the Fabric CLI `api` command. + +## Run Refresh On Demand + +To refresh a semantic model, you can use the `api` command as follows: + +```bash +fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" +``` + +Where `$SEMANTIC_MODEL_ID` and `$WORKSPACE_ID` are set to your semantic model ID and workspace ID respectively. + +## Run Refresh With Parameters + +You can also provide additional parameters to the refresh job, based on the supported payload documented in [Refresh Dataset In Group](https://learn.microsoft.com/rest/api/power-bi/datasets/refresh-dataset-in-group#request-body), as follows: + +```bash +REQUEST_BODY='{"retryCount":"1","timeout":"00:20:00"}' +fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" --show_headers -i "$REQUEST_BODY" +``` + +## Run Refresh With Polling for Completion + +Replace the following placeholders before running: + +- **`{WORKSPACE_ID}`** - Your workspace ID +- **`{SEMANTIC_MODEL_ID}`** - Your semantic model ID +- **`{POLLING_INTERVAL}`** - Polling interval in seconds + +=== "PowerShell" + ```powershell + # Configuration + $WorkspaceId = "{WORKSPACE_ID}" + $SemanticModelId = "{SEMANTIC_MODEL_ID}" + $PollingInterval = {POLLING_INTERVAL} # seconds + + # Customize the request body according to your needs + $requestBody = '{\"retryCount\":\"1\"}' + + $refreshResponse = fab api -A powerbi -X post "groups/$WorkspaceId/datasets/$SemanticModelId/refreshes" --show_headers -i $requestBody + + # Parse the response as JSON and check status code + + $refreshJson = $refreshResponse | ConvertFrom-Json + $statusCode = $refreshJson.status_code + + # Check POST response status (expecting 202 Accepted) + if ($statusCode -ne 202) { + exit 1 + } + + $pollingEndpoint = $null + + # Try to extract Location header first (preferred method) + if ($refreshJson.headers.Location) { + $locationUrl = $refreshJson.headers.Location + if ($locationUrl -match 'https?://[^/]+/v1\.0/myorg/(.+)') { + $pollingEndpoint = $Matches[1].Trim() + } + } + + # Fallback to RequestId header if Location not present + if (-not $pollingEndpoint) { + if ($refreshJson.headers.RequestId) { + $refreshId = $refreshJson.headers.RequestId + $pollingEndpoint = "groups/$WorkspaceId/datasets/$SemanticModelId/refreshes/$refreshId" + } + } + + if (-not $pollingEndpoint) { + exit 1 + } + + $status = "" + + while ($true) { + Start-Sleep -Seconds $PollingInterval + + $statusResponse = fab api -A powerbi $pollingEndpoint --show_headers + + $statusResponseJson = $statusResponse | ConvertFrom-Json + $getStatusCode = $statusResponseJson.status_code + + # Check GET response status (expecting 200 or 202) + if ($getStatusCode -ne 200 -and $getStatusCode -ne 202) { + Write-Host $statusResponse + } + + $statusJson = $statusResponseJson.text + + $status = if ($statusJson.extendedStatus) { $statusJson.extendedStatus } else { $statusJson.status } + + Write-Host " Refresh Status: $status" -ForegroundColor Cyan + + # Then handle completion states + switch -Regex ($status) { + "^Completed$" { + exit 0 + } + "^(Failed|Cancelled|Disabled|TimedOut)$" { + Write-Host $statusResponse + exit 1 + } + "^(NotStarted|InProgress|Unknown)$" { + # Continue polling + } + default { + Write-Host $statusResponse + exit 1 + } + } + } + ``` + +=== "Bash" + ```bash + #!/bin/bash + + # Configuration + WORKSPACE_ID="{WORKSPACE_ID}" + SEMANTIC_MODEL_ID="{SEMANTIC_MODEL_ID}" + POLLING_INTERVAL={POLLING_INTERVAL} # seconds + + # Customize the request body according to your needs + REQUEST_BODY='{"retryCount":"1"}' + + REFRESH_RESPONSE=$(fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" --show_headers -i "$REQUEST_BODY") + + # Parse the response as JSON and check status code + + REFRESH_JSON=$(echo "$REFRESH_RESPONSE" | jq '.') + STATUS_CODE=$(echo "$REFRESH_JSON" | jq -r '.status_code') + + # Check POST response status (expecting 202 Accepted) + if [ "$STATUS_CODE" != "202" ]; then + exit 1 + fi + + POLLING_ENDPOINT="" + + # Try to extract Location header first (preferred method) + LOCATION=$(echo "$REFRESH_JSON" | jq -r '.headers.Location // empty') + if [ -n "$LOCATION" ]; then + POLLING_ENDPOINT=$(echo "$LOCATION" | sed -n 's|.*https\?://[^/]*/v1\.0/myorg/\(.*\)|\1|p' | xargs) + fi + + # Fallback to RequestId header if Location not present + if [ -z "$POLLING_ENDPOINT" ]; then + REFRESH_ID=$(echo "$REFRESH_JSON" | jq -r '.headers.RequestId // empty') + if [ -n "$REFRESH_ID" ]; then + POLLING_ENDPOINT="groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes/$REFRESH_ID" + fi + fi + + if [ -z "$POLLING_ENDPOINT" ]; then + exit 1 + fi + + STATUS="" + + while true; do + sleep "$POLLING_INTERVAL" + + STATUS_RESPONSE=$(fab api -A powerbi "$POLLING_ENDPOINT" --show_headers) + + STATUS_RESPONSE_JSON=$(echo "$STATUS_RESPONSE" | jq '.') + GET_STATUS_CODE=$(echo "$STATUS_RESPONSE_JSON" | jq -r '.status_code') + + # Check GET response status (expecting 200 or 202) + if [ "$GET_STATUS_CODE" != "200" ] && [ "$GET_STATUS_CODE" != "202" ]; then + echo "$STATUS_RESPONSE" + fi + + STATUS_JSON=$(echo "$STATUS_RESPONSE_JSON" | jq -r '.text') + + EXTENDED_STATUS=$(echo "$STATUS_JSON" | jq -r '.extendedStatus // empty') + if [ -n "$EXTENDED_STATUS" ]; then + STATUS="$EXTENDED_STATUS" + else + STATUS=$(echo "$STATUS_JSON" | jq -r '.status') + fi + + echo " Refresh Status: $STATUS" + + # Then handle completion states + case "$STATUS" in + "Completed") + exit 0 + ;; + "Failed"|"Cancelled"|"Disabled"|"TimedOut") + echo "$STATUS_RESPONSE" + exit 1 + ;; + "NotStarted"|"InProgress"|"Unknown") + # Continue polling + ;; + *) + echo "$STATUS_RESPONSE" + exit 1 + ;; + esac + done + ``` diff --git a/mkdocs.yml b/mkdocs.yml index 3e797107..68d37d61 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -106,7 +106,9 @@ nav: - Auth Examples: examples/auth_examples.md - Config Examples: examples/config_examples.md - Core Management: - - API Examples: examples/api_examples.md + - API Examples: + - examples/api_examples.md + - Semantic Model Refresh: examples/refresh_semantic_model_example.md - ACL Examples: examples/acl_examples.md - Describe Examples: examples/desc_examples.md - Tenant Management: @@ -123,7 +125,6 @@ nav: - Workspace Examples: examples/workspace_examples.md - Item Management: - Item Examples: examples/item_examples.md - - Dataset Refresh Example: examples/refresh_dataset_example.md - Job Examples: examples/job_examples.md - Label Examples: examples/label_examples.md - Data & Storage: From 9e31ad65fc4ac2f54d4c78ef907f15f08e493f00 Mon Sep 17 00:00:00 2001 From: may-hartov Date: Tue, 17 Feb 2026 08:41:29 +0200 Subject: [PATCH 3/4] fixes changie text --- .changes/unreleased/docs-20260216-084028.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/unreleased/docs-20260216-084028.yaml b/.changes/unreleased/docs-20260216-084028.yaml index f61e9a90..987417e5 100644 --- a/.changes/unreleased/docs-20260216-084028.yaml +++ b/.changes/unreleased/docs-20260216-084028.yaml @@ -1,5 +1,5 @@ kind: docs -body: Created refresh dataset using API command example +body: Created refresh semantic model using API command example time: 2026-02-16T08:40:28.503495133Z custom: Author: may-hartov From 78fbef103161823d498e87d20be277a13740c76b Mon Sep 17 00:00:00 2001 From: may-hartov Date: Tue, 17 Feb 2026 12:36:17 +0200 Subject: [PATCH 4/4] CR fixes --- docs/examples/refresh_semantic_model_example.md | 15 ++++++++++++--- mkdocs.yml | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/examples/refresh_semantic_model_example.md b/docs/examples/refresh_semantic_model_example.md index a120019c..617e380e 100644 --- a/docs/examples/refresh_semantic_model_example.md +++ b/docs/examples/refresh_semantic_model_example.md @@ -17,11 +17,20 @@ Where `$SEMANTIC_MODEL_ID` and `$WORKSPACE_ID` are set to your semantic model ID You can also provide additional parameters to the refresh job, based on the supported payload documented in [Refresh Dataset In Group](https://learn.microsoft.com/rest/api/power-bi/datasets/refresh-dataset-in-group#request-body), as follows: ```bash -REQUEST_BODY='{"retryCount":"1","timeout":"00:20:00"}' -fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" --show_headers -i "$REQUEST_BODY" +fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" --show_headers -i '{"retryCount":"1","timeout":"00:20:00"}' ``` -## Run Refresh With Polling for Completion +## Check Refresh Status + +You can check the status of a specific refresh operation using the refresh ID. The refresh ID is returned in the `Location` or `RequestId` response headers when you run a refresh. + +```bash +fab api -A powerbi -X get "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes/$REFRESH_ID" +``` + +This command uses the [Get Refresh Execution Details In Group](https://learn.microsoft.com/en-us/rest/api/power-bi/datasets/get-refresh-execution-details-in-group) API endpoint. + +## End-to-End Example: Run Refresh and Poll for Completion Replace the following placeholders before running: diff --git a/mkdocs.yml b/mkdocs.yml index 68d37d61..89e315dd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -108,7 +108,7 @@ nav: - Core Management: - API Examples: - examples/api_examples.md - - Semantic Model Refresh: examples/refresh_semantic_model_example.md + - Example of semantic model refresh: examples/refresh_semantic_model_example.md - ACL Examples: examples/acl_examples.md - Describe Examples: examples/desc_examples.md - Tenant Management: