同僚: プログラムで RDL ファイルを Power BI にあげたいけどどうしたらいい?
私: え、Power BI って RDL サポートしてるんだ。。まじか
というやり取りが今朝あり、調査したので結果を共有しておきます。
RDL on Power BI
そうなんです。Power BI は RDL を "ページ分割されたレポート" としてサポートしていたのです。とりあえず チュートリアル:ページ分割されたレポートを作成して Power BI サービスにアップロードする を一通りやって勉強しました。いいチュートリアルなので是非お試しください。
API 経由でのアップロード
本題の RDL ファイルを API 経由でアップロードする方法ですが、Power BI の API は Power BI REST APIs に詳細が公開されています。
ドキュメントを見た結果、以下の手順で行けることが分かりました。
- Post Import In Group API を使って RDL ファイルをインポートする。この過程でレポートが作成される。
- Get Import In Group を使ってインポートの情報と取得する。結果として作成されたレポートの情報も取得できる。
RDL ファイルのアップロードのみであればこれで終わりですが、データソースの資格情報を手動で入れたくないので、そのやり方も調べておきました。
- Reports - Get Datasources In Group API でレポートに紐づくデータソースの情報を取得する。ここでゲートウェイとデータソースの情報が取得できる。
- Gateways - Update Datasource API を使って資格情報を設定する。
これだけです。
PowerShell の例
以前紹介したとおり、オフィシャルの Power BI PowerShell モジュールがあり、今回もそちらを使いました。一部機能がまだサポートされていないため、そこは PowerShell の機能で書いてみました。PR 作らないとなぁ。
function Publish-ImportRDLFile
{
param
(
[string]$RdlFilePath,
[string]$GroupId,
[string]$nameConflict = "Abort"
)
# RDL ファイルから 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--
"@
# アクセストークンをヘッダーに設定
$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"
}
# インポート作成
$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
)
# アクセストークンをヘッダーに設定
$headers = Get-PowerBIAccessToken
# 作成したインポートからレポート情報を取得。時間かかる場合があるので取れるまで繰り返し。
$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 情報を取得
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
# 最後に認証を設定。
$url = "https://api.powerbi.com/v1.0/myorg/gateways/$gatewayId/datasources/$datasourceId"
# ここは基本認証の例だが、他の例は 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
}
# Power BI に接続
Connect-PowerBIServiceAccount
$groupId = "<group id>"
# インポート作成
$id = Publish-ImportRDLFile -GroupId $groupId -RdlFilePath "<path to rdl file>"
# 資格情報を設定
Set-BasicPassword-To-RDL -Id $id -GroupId $groupId -UserName "<username>" -Password "<password>"
まとめ
Power BI は充実した API を公開しているので、自動化したい場合は色々試してください。