Continuous Deployment of Power BI Reports with PowerShell and Azure DevOps

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’ve created a Script which can start a pipeline.

The script contains four parameters:

The UPN / username who can start the pipeline
The password from the user (if the password contains special characters, you should put the password into single quotes.
The stage: 0=from DEV to test, 1=from test to prod
The pipeline name

pipeline.ps1 username 'password' 1 DeployPipeline

So, you can call the script for different pipelines and for the different stages.
The script:

[CmdletBinding()]
param (
    $ParamUser,
    $ParamPassword,
    $ParamstageOrder, # The order of the source stage. Development (0), Test (1).
    $ParamPipelinename # The name of the pipeline
)

$myPassword = $ParamPassword
$myUsername = $ParamUser
$stageOrder = $ParamstageOrder   
$pipelineName = $ParamPipelinename  

$moduleName = "MicrosoftPowerBIMgmt.Profile"
$module = Get-Module $moduleName -ListAvailable -ErrorAction SilentlyContinue

if (!$module) 
{
	Install-Module -Name $moduleName -Force -Scope CurrentUser -SkipPublisherCheck 
}


$password = ConvertTo-SecureString $myPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($myUsername, $password)

Login-PowerBIServiceAccount -Credential $credential
                  

# End Parameters =======================================

try { 
    # Get pipelines
    $pipelines = (Invoke-PowerBIRestMethod -Url "pipelines"  -Method Get | ConvertFrom-Json).value

    # Try to find the pipeline by display name
    $pipeline = $pipelines | Where-Object {$_.DisplayName -eq $pipelineName}

    if(!$pipeline) {
        Write-Host "A pipeline with the requested name was not found"
        return
    }

    # Construct the request url and body
    $url = "pipelines/{0}/DeployAll" -f $pipeline.Id

    $body = @{ 
        sourceStageOrder = $stageOrder

        options = @{
            # Allows creating new artifact if needed on the Test stage workspace
            allowCreateArtifact = $TRUE

            # Allows overwriting existing artifact if needed on the Test stage workspace
            allowOverwriteArtifact = $TRUE
        }
    } | ConvertTo-Json

    # Send the request
    $deployResult = Invoke-PowerBIRestMethod -Url $url  -Method Post -Body $body | ConvertFrom-Json

    "Operation ID: {0}" -f $deployResult.id
} catch {
    $errmsg = Resolve-PowerBIError -Last
    $errmsg.Message
}

I moved this script to a DevOps repo:

After that, I created a release pipeline:

The content of each stage:

After running the pipeline, the content of each stage is synchronized: