{"id":1687,"date":"2026-10-10T14:03:11","date_gmt":"2026-10-10T12:03:11","guid":{"rendered":"https:\/\/www.flip-design.de\/?p=1687"},"modified":"2026-10-10T14:03:11","modified_gmt":"2026-10-10T12:03:11","slug":"power-bi-fabric-automated-deployment-with-azure-devops-and-powershell","status":"publish","type":"post","link":"https:\/\/www.flip-design.de\/?p=1687","title":{"rendered":"Power BI &amp; Fabric: Automated Deployment with Azure DevOps and PowerShell"},"content":{"rendered":"\n<p>In this post, I\u2019ll briefly demonstrate how to trigger a deployment pipeline in Microsoft Fabric using PowerShell. The deployment requires the IDs of the source and target stages\u2014for example, when deploying from Test to Production. I\u2019ve adapted the script so that only the source stage number needs to be specified. The script automatically retrieves the corresponding IDs and uses the next stage as the target. This simplifies configuration and deployment.<\/p>\n\n\n\n<p>The following screenshot shows a deployment pipeline with three stages. The pipeline ID can be found in its URL. This ID is required to trigger the deployment through the script.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image.png\"><img decoding=\"async\" loading=\"lazy\" width=\"940\" height=\"459\" src=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image.png\" alt=\"\" class=\"wp-image-1688\" srcset=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image.png 940w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image-300x146.png 300w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image-768x375.png 768w\" sizes=\"(max-width: 940px) 100vw, 940px\" \/><\/a><\/figure>\n\n\n\n<p>I\u2019ve also created a YAML pipeline in Azure DevOps that runs the PowerShell script. The configuration of this YAML pipeline is outside the scope of this post. A parameter makes it easy to select the source stage: for example, specifying 1 deploys from Development to Test, while specifying 2 deploys from Test to Production.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image-1.png\"><img decoding=\"async\" loading=\"lazy\" width=\"940\" height=\"459\" src=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image-1.png\" alt=\"\" class=\"wp-image-1689\" srcset=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image-1.png 940w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image-1-300x146.png 300w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2026\/10\/image-1-768x375.png 768w\" sizes=\"(max-width: 940px) 100vw, 940px\" \/><\/a><\/figure>\n\n\n\n<p>Here is the script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;#\r\n.SYNOPSIS\r\n    Starts a deployment between two consecutive Fabric pipeline stages.\r\n\r\n.DESCRIPTION\r\n    Authenticates using a service principal and retrieves the stages\r\n    of the specified deployment pipeline.\r\n\r\n    Stages are sorted by their pipeline order. The Stage parameter\r\n    selects the source stage using a one-based position.\r\n    The next stage in the sorted list is used as the target.\r\n\r\n    The actual stage IDs are retrieved automatically and passed\r\n    to the deployment API.\r\n\r\n    The script starts the deployment but does not wait for completion.\r\n\r\n.PARAMETER TenantId\r\n    Microsoft Entra tenant ID.\r\n\r\n.PARAMETER ClientId\r\n    Application (client) ID of the service principal.\r\n\r\n.PARAMETER ClientSecret\r\n    Client secret used to authenticate the service principal.\r\n    When running in a pipeline, supply this value from a secret variable.\r\n\r\n.PARAMETER PipelineId\r\n    ID of the Fabric deployment pipeline.\r\n\r\n.PARAMETER Stage\r\n    One-based position of the source stage. Defaults to 1.\r\n\r\n    For a pipeline with Development, Test, and Production stages:\r\n    1 deploys from Development to Test.\r\n    2 deploys from Test to Production.\r\n\r\n    The final stage cannot be selected as the source because\r\n    it has no subsequent target stage.\r\n\r\n.EXAMPLE\r\n    $parameters = @{\r\n        TenantId     = \"&lt;tenant-id>\"\r\n        ClientId     = \"&lt;client-id>\"\r\n        ClientSecret = $env:FABRIC_CLIENT_SECRET\r\n        PipelineId   = \"&lt;pipeline-id>\"\r\n        Stage        = 1\r\n    }\r\n\r\n    .\\Deploy-FabricPipeline.ps1 @parameters\r\n\r\n    Starts a deployment from the first stage to the second stage.\r\n#>\r\n\r\nparam(\r\n    &#91;Parameter(Mandatory = $true)]\r\n    &#91;ValidateNotNullOrEmpty()]\r\n    &#91;string]$TenantId,\r\n\r\n    &#91;Parameter(Mandatory = $true)]\r\n    &#91;ValidateNotNullOrEmpty()]\r\n    &#91;string]$ClientId,\r\n\r\n    &#91;Parameter(Mandatory = $true)]\r\n    &#91;ValidateNotNullOrEmpty()]\r\n    &#91;string]$ClientSecret,\r\n\r\n    &#91;Parameter(Mandatory = $true)]\r\n    &#91;ValidateNotNullOrEmpty()]\r\n    &#91;string]$PipelineId,\r\n\r\n    &#91;ValidateRange(1, 9)]\r\n    &#91;int]$Stage = 1\r\n)\r\n\r\n# Stop script execution if an operation fails.\r\n$ErrorActionPreference = \"Stop\"\r\n\r\n# Authenticate using the OAuth 2.0 client credentials flow.\r\n$tokenParameters = @{\r\n    Method      = \"Post\"\r\n    Uri         = \"https:\/\/login.microsoftonline.com\/$TenantId\/oauth2\/v2.0\/token\"\r\n    ContentType = \"application\/x-www-form-urlencoded\"\r\n    Body        = @{\r\n        grant_type    = \"client_credentials\"\r\n        client_id     = $ClientId\r\n        client_secret = $ClientSecret\r\n        scope         = \"https:\/\/api.fabric.microsoft.com\/.default\"\r\n    }\r\n}\r\n\r\n$token = Invoke-RestMethod @tokenParameters\r\n\r\n# Prepare the authorization header and deployment pipeline URL.\r\n$headers = @{\r\n    Authorization = \"Bearer $($token.access_token)\"\r\n}\r\n\r\n$url = \"https:\/\/api.fabric.microsoft.com\/v1\/deploymentPipelines\/$PipelineId\"\r\n\r\n# Retrieve all stages and sort them by their pipeline order.\r\n$result = Invoke-RestMethod -Method Get -Uri \"$url\/stages\" -Headers $headers\r\n$stages = @($result.value | Sort-Object -Property order)\r\n\r\n# Verify that the selected source stage has a subsequent target stage.\r\nif ($Stage -ge $stages.Count) {\r\n    throw \"Source stage position $Stage has no subsequent target stage. The pipeline contains $($stages.Count) stage(s).\"\r\n}\r\n\r\n# Convert the one-based source position to a zero-based array index.\r\n# The next array element represents the target stage.\r\n$source = $stages&#91;$Stage - 1]\r\n$target = $stages&#91;$Stage]\r\n\r\n# Build the request body using the actual stage IDs.\r\n$body = @{\r\n    sourceStageId = $source.id\r\n    targetStageId = $target.id\r\n} | ConvertTo-Json\r\n\r\n# Submit the deployment request.\r\n$deploymentParameters = @{\r\n    Method      = \"Post\"\r\n    Uri         = \"$url\/deploy\"\r\n    Headers     = $headers\r\n    ContentType = \"application\/json\"\r\n    Body        = $body\r\n}\r\n\r\nInvoke-RestMethod @deploymentParameters\r\n\r\n# Report that the request was submitted, not that deployment has completed.\r\nWrite-Host \"Deployment started: $($source.displayName) -> $($target.displayName)\"\r\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In this post, I\u2019ll briefly demonstrate how to trigger a deployment pipeline in Microsoft Fabric using PowerShell. The deployment requires the IDs of the source and target stages\u2014for example, when deploying from Test to Production. I\u2019ve adapted the script so &hellip; <a href=\"https:\/\/www.flip-design.de\/?p=1687\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/posts\/1687"}],"collection":[{"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1687"}],"version-history":[{"count":1,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/posts\/1687\/revisions"}],"predecessor-version":[{"id":1690,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/posts\/1687\/revisions\/1690"}],"wp:attachment":[{"href":"https:\/\/www.flip-design.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1687"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1687"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1687"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}