Upload RDL file(s) to Power BI via API
Tags: powerbi, rdl, powershell
Published: 2020-02-07 07:17:53

---
title: Upload RDL file(s) to Power BI via API
published: true
description: Upload RDL file(s) to Power BI via API
tags: powerbi,rdl,powershell
---

Today, my good friend asked me how to upload RDL file(s) to Power BI.
And my answer was "What? Power BI supports RDL now???" :)

At the end, this is my research results.

# RDL on Power BI (premium)

Yes, it's true that Power BI Online supports RDL as "Paginated Report".
I followed [Tutorial: Create a paginated report and upload it to the Power BI service](https://docs.microsoft.com/en-us/power-bi/paginated-reports/paginated-reports-quickstart-aw#upload-the-report-to-the-service) to learn how to do it manually.

# How to upload RDL via API

Now time to research how to upload RDL. Power BI team provide comprehensive API documentation at [Power BI REST APIs](https://docs.microsoft.com/en-us/rest/api/power-bi/) 

I looked through the documentation and figured out this is how it works.

1. Use [Post Import In Group API](https://docs.microsoft.com/en-us/rest/api/power-bi/imports/postimportingroup) to import RDL file from local disk, which creates RDL (or Paginated Report) repot in Power BI Online.
1. Use [Get Import In Group](https://docs.microsoft.com/en-us/rest/api/power-bi/imports/getimportingroup) to get the import result which contains created report information.

If I only want to upload RDL files, then that's it. However, I had to set data source credential manually, so I did further research. And this is how to set credential.

1. Use [Reports - Get Datasources In Group API](https://docs.microsoft.com/en-us/rest/api/power-bi/reports/getdatasourcesingroup) to get the datasource for the report, which returns gateway and datasource information.
1. Use [Gateways - Update Datasource API](https://docs.microsoft.com/en-us/rest/api/power-bi/gateways/updatedatasource) to set the credential.

Okay that's it!

# PowerShell exmple

There is an official Power BI PowerShell module, and I partially used it. I may need to contribute the module so that it supports entire workflow.

This is far from perfect but I hope you get some idea. 
* Please change Encoding from UTF8 to whatever your file is when you **Get-Content**

```powershell
function Publish-ImportRDLFile 
{
    param
    (
        [string]$RdlFilePath,
        [string]$GroupId,
        [string]$nameConflict = "Abort"
    )

    # Get file content and create body
    $fileName = [IO.Path]::GetFileName($RdlFilePath)
    $boundary = [guid]::NewGuid().ToString()
    $fileBody = Get-Content -Path $RdlFilePath -Encoding UTF8
    
    $body = @"
----FormBoundary$boundary
Content-Disposition: form-data; name="$filename"; filename="$filename"
Content-Type: application/rdl

$fileBody 
----FormBoundary$boundary--

"@
    
    # Get AccessToken and set it as header.
    $headers = Get-PowerBIAccessToken

    if ($GroupId) {
        $url = "https://api.powerbi.com/v1.0/myorg/groups/$GroupId/imports?datasetDisplayName=$fileName&nameConflict=$nameConflict"
    }
    else {
        $url = "https://api.powerbi.com/v1.0/myorg/imports?datasetDisplayName=$fileName&nameConflict=$nameConflict"
    }

    # Create import
    $report = Invoke-RestMethod -Uri $url -Method Post -Headers $headers -Body $body -ContentType "multipart/form-data"   
    $report.id
}

function Set-BasicPassword-To-RDL 
{
    param
    (
        [string]$Id,
        [string]$GroupId,
        [string]$UserName,
        [string]$Password
    )
        
    # Get AccessToken and set it as header.
    $headers = Get-PowerBIAccessToken

    # Get import result first. As it may take a bit of time until report is created, so repeat until I can get report Id
    $reportId = $null
    while($reportId -eq $null)
    {
        if ($GroupId) {
            $url = "https://api.powerbi.com/v1.0/myorg/groups/$GroupId/imports/$Id"
        }
        else {
            $url = "https://api.powerbi.com/v1.0/myorg/imports/$Id"
        }

        $import = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
        $reportId = $import.reports.id
    }

    # Datasource information
    if ($GroupId) {
        $url = "https://api.powerbi.com/v1.0/myorg/groups/$GroupId/reports/$reportId/datasources"
    }
    else {
        $url = "https://api.powerbi.com/v1.0/myorg/reports/$reportId/datasources"
    }

    $datasources = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
    $gatewayId = $datasources.value[0].gatewayId
    $datasourceId = $datasources.value[0].datasourceId
     
    # Finallly set credential. No Uri difference between myworkspace and group workspace.
    $url = "https://api.powerbi.com/v1.0/myorg/gateways/$gatewayId/datasources/$datasourceId"
        
    # This is a sample for basic authentication. Find more samples at https://docs.microsoft.com/en-us/rest/api/power-bi/gateways/updatedatasource#examples
    $body = @"
{
  "credentialDetails": {
	"credentialType":"Basic",
	"credentials": "{\"credentialData\":[{\"name\":\"username\", \"value\":\"$UserName\"},{\"name\":\"password\", \"value\":\"$Password\"}]}",
	"encryptedConnection": "Encrypted",
    "encryptionAlgorithm": "None",
    "privacyLevel": "None"
	}
}
"@
    $datasources = Invoke-RestMethod -Uri $url -Method Patch -Headers $headers -ContentType "application/json" -Body $body
}

# Connect to Power BI.
Connect-PowerBIServiceAccount

$groupId = "<group id>"
# Create Import
$id = Publish-ImportRDLFile -GroupId $groupId -RdlFilePath "<path to rdl file>"
# Set password
Set-BasicPassword-To-RDL -Id $id -GroupId $groupId -UserName "<username>" -Password "<password>"
```

# Summary

Power BI provides powerful Web API for developer. Whenever you need some automation, check it out!

# Reference

[Power BI Community Get Help: REST import rdl files](https://community.powerbi.com/t5/Developer/REST-import-rdl-files/td-p/708986)