{"id":1092,"date":"2021-12-20T20:10:03","date_gmt":"2021-12-20T18:10:03","guid":{"rendered":"https:\/\/www.flip-design.de\/?p=1092"},"modified":"2021-12-20T20:10:03","modified_gmt":"2021-12-20T18:10:03","slug":"continuous-deployment-of-power-bi-reports-with-powershell-and-azure-devops","status":"publish","type":"post","link":"https:\/\/www.flip-design.de\/?p=1092","title":{"rendered":"Continuous Deployment of Power BI Reports with PowerShell and Azure DevOps"},"content":{"rendered":"\n<p>For Azure DevOps you find several Addons to deploy Power BI Content to a workspace and addons to trigger a Pipeline. But when you need more flexibility to trigger a pipeline at Power BI and decide which content you want to deploy, you can use the Power BI REST API bs triggering it with PowerShell. For this purpose, I\u2019ve created a Script which can start a pipeline.<\/p>\n\n\n\n<p>The script contains four parameters:<br><\/p>\n\n\n\n<p>The UPN \/ username who can start the pipeline<br>The password from the user (if the password contains special characters, you should put the password into single quotes.<br>The stage: 0=from DEV to test, 1=from test to prod<br>The pipeline name<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pipeline.ps1 username 'password' 1 DeployPipeline\r<\/code><\/pre>\n\n\n\n<p>So, you can call the script for different pipelines and for the different stages.<br>The script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;CmdletBinding()]\r\nparam (\r\n    $ParamUser,\r\n    $ParamPassword,\r\n    $ParamstageOrder, # The order of the source stage. Development (0), Test (1).\r\n    $ParamPipelinename # The name of the pipeline\r\n)\r\n\r\n$myPassword = $ParamPassword\r\n$myUsername = $ParamUser\r\n$stageOrder = $ParamstageOrder   \r\n$pipelineName = $ParamPipelinename  \r\n\r\n$moduleName = \"MicrosoftPowerBIMgmt.Profile\"\r\n$module = Get-Module $moduleName -ListAvailable -ErrorAction SilentlyContinue\r\n\r\nif (!$module) \r\n{\r\n\tInstall-Module -Name $moduleName -Force -Scope CurrentUser -SkipPublisherCheck \r\n}\r\n\r\n\r\n$password = ConvertTo-SecureString $myPassword -AsPlainText -Force\r\n$credential = New-Object System.Management.Automation.PSCredential ($myUsername, $password)\r\n\r\nLogin-PowerBIServiceAccount -Credential $credential\r\n                  \r\n\r\n# End Parameters =======================================\r\n\r\ntry { \r\n    # Get pipelines\r\n    $pipelines = (Invoke-PowerBIRestMethod -Url \"pipelines\"  -Method Get | ConvertFrom-Json).value\r\n\r\n    # Try to find the pipeline by display name\r\n    $pipeline = $pipelines | Where-Object {$_.DisplayName -eq $pipelineName}\r\n\r\n    if(!$pipeline) {\r\n        Write-Host \"A pipeline with the requested name was not found\"\r\n        return\r\n    }\r\n\r\n    # Construct the request url and body\r\n    $url = \"pipelines\/{0}\/DeployAll\" -f $pipeline.Id\r\n\r\n    $body = @{ \r\n        sourceStageOrder = $stageOrder\r\n\r\n        options = @{\r\n            # Allows creating new artifact if needed on the Test stage workspace\r\n            allowCreateArtifact = $TRUE\r\n\r\n            # Allows overwriting existing artifact if needed on the Test stage workspace\r\n            allowOverwriteArtifact = $TRUE\r\n        }\r\n    } | ConvertTo-Json\r\n\r\n    # Send the request\r\n    $deployResult = Invoke-PowerBIRestMethod -Url $url  -Method Post -Body $body | ConvertFrom-Json\r\n\r\n    \"Operation ID: {0}\" -f $deployResult.id\r\n} catch {\r\n    $errmsg = Resolve-PowerBIError -Last\r\n    $errmsg.Message\r\n}<\/code><\/pre>\n\n\n\n<p>I moved this script to a DevOps repo:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-10.png\"><img decoding=\"async\" loading=\"lazy\" width=\"945\" height=\"503\" src=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-10.png\" alt=\"\" class=\"wp-image-1093\" srcset=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-10.png 945w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-10-300x160.png 300w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-10-768x409.png 768w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-10-500x266.png 500w\" sizes=\"(max-width: 945px) 100vw, 945px\" \/><\/a><\/figure>\n\n\n\n<p>After that, I created a release pipeline:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-11.png\"><img decoding=\"async\" loading=\"lazy\" width=\"945\" height=\"503\" src=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-11.png\" alt=\"\" class=\"wp-image-1094\" srcset=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-11.png 945w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-11-300x160.png 300w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-11-768x409.png 768w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-11-500x266.png 500w\" sizes=\"(max-width: 945px) 100vw, 945px\" \/><\/a><\/figure>\n\n\n\n<p>The content of each stage:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-12.png\"><img decoding=\"async\" loading=\"lazy\" width=\"945\" height=\"503\" src=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-12.png\" alt=\"\" class=\"wp-image-1095\" srcset=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-12.png 945w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-12-300x160.png 300w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-12-768x409.png 768w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-12-500x266.png 500w\" sizes=\"(max-width: 945px) 100vw, 945px\" \/><\/a><\/figure>\n\n\n\n<p>After running the pipeline, the content of each stage is synchronized:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-13.png\"><img decoding=\"async\" loading=\"lazy\" width=\"945\" height=\"503\" src=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-13.png\" alt=\"\" class=\"wp-image-1096\" srcset=\"https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-13.png 945w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-13-300x160.png 300w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-13-768x409.png 768w, https:\/\/www.flip-design.de\/wp-content\/uploads\/2021\/12\/image-13-500x266.png 500w\" sizes=\"(max-width: 945px) 100vw, 945px\" \/><\/a><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>For Azure DevOps you find several Addons to deploy Power BI Content to a workspace and addons to trigger a Pipeline. But when you need more flexibility to trigger a pipeline at Power BI and decide which content you want &hellip; <a href=\"https:\/\/www.flip-design.de\/?p=1092\">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\/1092"}],"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=1092"}],"version-history":[{"count":1,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/posts\/1092\/revisions"}],"predecessor-version":[{"id":1097,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=\/wp\/v2\/posts\/1092\/revisions\/1097"}],"wp:attachment":[{"href":"https:\/\/www.flip-design.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.flip-design.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}