Power BI のストリーミングデータセットについては、ポータルから簡単に作成することができます。
Power BI のリアルタイム ストリーミング
投稿作成時点では、ポータルから作成した、ストリーミングデータセットについては、Power BI デスクトップの「Power BI サービスからのデータの取得」では使用することができないため、PowerShell で Power BI のプッシュデータセットを作成してみました。
プッシュデータセットであれば、複数のテーブルをデータセットに含めることもできますので、ストリーミングデータセットより高度な内容ができるかと。
基本的な流れと REST API については以下の情報を参考にするとよいかと思います。
- Power BI データセットにデータをプッシュする
- Power BI REST API リファレンス
- Power BI デベロッパー センター
- Register an Application for Power BI
- Apiary での Power BI REST API
- powerbi-powershell-modules
今回は、Power BI Free プランのユーザーを使用しますので、ユーザーについては最初に用意をしておきます。
■Azure AD にアプリケーションを登録
最初に、Azure AD にアプリケーションの登録が必要となります。
登録に関してはポータルから実施してしまうのがよいかと。
Register an Application for Power BI
今回は以下のような設定でアプリケーションを Azure AD に登録しています。
(Redirect URL には「https://login.live.com/oauth20_desktop.srf」を設定しています)
「Register App」をクリックすると「アプリケーション ID (クライアント ID)」が表示されますので、ID を控えておきます。
シークレット (キー) ではないので、アプリケーション ID については、Azure ポータルから再度確認可能です。
今回は、対話型のアクセス許可の要求をスキップしたいため、登録したアプリケーションの「必要なアクセス許可」から「アクセス許可の付与」をクリックして、裏でアクセス許可を設定しておきます。
■データセットの作成
Azure AD の設定が終わったら次にデータセットの作成を行います。
データセットの作成
今回は以下のようなスクリプトでデータセットを作成しています。
(スクリプトでなく Apiary での Power BI REST API で REST をたたいてもよいかと)
このデータセットについては、Live Monitor のデータ連携用として使用する想定です。
user / password はデータセットを作成するユーザーの情報、clientID は AAD に登録したアプリケーションのアプリケーション ID、tenantid は は AAD のテナント ID を指定します。
Param( [Parameter(Mandatory)] [string]$user, [Parameter(Mandatory)] [string]$password, [Parameter(Mandatory)] [string]$clientID, [Parameter(Mandatory)] [string]$tenantid ) # 指定したユーザーにデータセットの作成 $redirectUri = "https://login.live.com/oauth20_desktop.srf" $resourceUri = "https://analysis.windows.net/powerbi/api" $authorityUri = "https://login.windows.net/common/oauth2/authorize" $powerBIApiUrl = "https://api.powerbi.com/v1.0/myorg" $tokenendpoint = "https://login.windows.net/{0}/oauth2/token" -f $tennantid $Body = @{ "resource"= $resourceUri "client_id" = $clientID "grant_type" = "password" "username" = $user "password" = $password } $params = @{ ContentType = "application/x-www-form-urlencoded" Headers = @{"accept"="application/json"} Body = $Body Method = "Post" URI = $TokenEndpoint } $token = Invoke-RestMethod @params ######################################################## # データセットの作成 ######################################################## $json = @" {"name": "Live Monitor Dataset","tables": [ {"name": "LiveMonitor", "columns": [ {"name" : "Counter Date", "dataType": "DateTime"}, {"name" : "Server Name", "dataType": "string"}, {"name" : "CPU Usage %", "dataType": "Double"}, {"name" : "Buffer Cache Hit %", "dataType": "Double"}, {"name" : "Plan Cache Hit %", "dataType": "Double"}, {"name" : "Page life expectancy", "dataType": "Double"}, {"name" : "Database Cache Memory (MB)", "dataType": "Double"}, {"name" : "Plan Chache Memory (MB)", "dataType": "Double"}, {"name" : "Free Memory (MB)", "dataType": "Double"}, {"name" : "Total Server Memory (MB)", "dataType": "Double"}, {"name" : "Target Server Memory (MB)", "dataType": "Double"}, {"name" : "Granted Workspace Memory (MB)", "dataType": "Double"}, {"name" : "Memory Grants Outstanding", "dataType": "Double"}, {"name" : "Memory Grants Pending", "dataType": "Double"}, {"name" : "Batch Requests/sec", "dataType": "Double"}, {"name" : "Page lookups (MB)/sec", "dataType": "Double"}, {"name" : "Readahead pages (MB)/sec", "dataType": "Double"}, {"name" : "Page reads (MB)/sec", "dataType": "Double"}, {"name" : "Page writes (MB)/sec", "dataType": "Double"}, {"name" : "Checkpoint pages (MS)/sec", "dataType": "Double"}, {"name" : "Background writer pages (MB)/sec", "dataType": "Double"}, {"name" : "Log Flushes/sec", "dataType": "Double"}, {"name" : "Log MBytes Flushed/sec", "dataType": "Double"}, {"name" : "Log Flush Waits/sec", "dataType": "Double"}, {"name" : "Log Flush Wait Time", "dataType": "Double"}, {"name" : "SQL Compilations/sec", "dataType": "Double"}, {"name" : "SQL Re-Compilations/sec", "dataType": "Double"} ] } ] } "@ $bytes = [System.Text.Encoding]::UTF8.GetBytes($json) $uri = [System.Uri]::EscapeUriString(("{0}/datasets" -f $powerBIApiUrl)) $ret = Invoke-WebRequest -Method Post -ContentType "application/json" -Headers @{Authorization=("Bearer {0}" -f $token.access_token)} -Uri $uri -Body $bytes return ($ret.Content | ConvertFrom-Json)
スクリプトを実行するとデータセットの ID が取得できます。
データセットの ID については、データセットにデータを登録する際に必要となりますので控えておきます。
データセットの ID を取得するための REST もありますが、ポータルの URL からも ID は確認可能です。
■データセットにデータをプッシュ
データセットの作成が終わったらデータをプッシュします。
データのプッシュについては以下のスクリプトを使用しています。
Live Monitor で取得した内容をプッシュするスクリプトとなっています。
Param( [Parameter(Mandatory)] [string]$user, [Parameter(Mandatory)] [string]$password, [Parameter(Mandatory)] [string]$clientID, [Parameter(Mandatory)] [string]$tenantid, [Parameter(Mandatory)] [string]$datasetid, [Parameter(Mandatory)] [string]$ConnectionString ) $redirectUri = "https://login.live.com/oauth20_desktop.srf" $resourceUri = "https://analysis.windows.net/powerbi/api" $authorityUri = "https://login.windows.net/common/oauth2/authorize" $powerBIApiUrl = "https://api.powerbi.com/v1.0/myorg" $tokenendpoint = "https://login.windows.net/{0}/oauth2/token" -f $tennantid $con = New-Object System.Data.SqlClient.SqlConnection $con.ConnectionString = $ConnectionString $con.Open() $cmd = $con.CreateCommand() $cmd.CommandText = "usp_LiveMonitor" $da = New-Object System.Data.SqlClient.SqlDataAdapter $da.SelectCommand = $cmd $ds = New-Object System.Data.DataSet $count = $da.Fill($ds) $tmp = $ds.Tables[0] | select $ds.Tables[0].Columns.columnname | ConvertTo-Json | ConvertFrom-Json $datetime = (Get-Date ([System.TimeZoneInfo]::ConvertTimeFromUtc((Get-Date).ToUniversalTime(), ([System.TimeZoneInfo]::FindSystemTimeZoneById("Tokyo Standard Time")))) -format s) $pushdata = @" {"rows": [ { "Counter Date":"$($datetime)", "Server Name":"$($tmp.'Server Name')", "CPU Usage %":$($tmp.'CPU Usage %'), "Buffer Cache Hit %":$($tmp.'Buffer Cache Hit %'), "Plan Cache Hit %":$($tmp.'Plan Cache Hit %'), "Page life expectancy":$($tmp.'Page life expectancy'), "Database Cache Memory (MB)":$($tmp.'Database Cache Memory (MB)'), "Plan Chache Memory (MB)":$($tmp.'Plan Chache Memory (MB)'), "Free Memory (MB)":$($tmp.'Free Memory (MB)'), "Total Server Memory (MB)":$($tmp.'Total Server Memory (MB)'), "Target Server Memory (MB)":$($tmp.'Target Server Memory (MB)'), "Granted Workspace Memory (MB)":$($tmp.'Granted Workspace Memory (MB)'), "Memory Grants Outstanding":$($tmp.'Memory Grants Outstanding'), "Memory Grants Pending":$($tmp.'Memory Grants Pending'), "Batch Requests/sec":$($tmp.'Batch Requests/sec'), "Page lookups (MB)/sec":$($tmp.'Page lookups (MB)/sec'), "Readahead pages (MB)/sec":$($tmp.'Readahead pages (MB)/sec'), "Page reads (MB)/sec":$($tmp.'Page reads (MB)/sec'), "Page writes (MB)/sec":$($tmp.'Page writes (MB)/sec'), "Checkpoint pages (MS)/sec":$($tmp.'Checkpoint pages (MS)/sec'), "Background writer pages (MB)/sec":$($tmp.'Background writer pages (MB)/sec'), "Log Flushes/sec":$($tmp.'Log Flushes/sec'), "Log MBytes Flushed/sec":$($tmp.'Log MBytes Flushed/sec'), "Log Flush Waits/sec":$($tmp.'Log Flush Waits/sec'), "Log Flush Wait Time":$($tmp.'Log Flush Wait Time'), "SQL Compilations/sec":$($tmp.'SQL Compilations/sec'), "SQL Re-Compilations/sec":$($tmp.'SQL Re-Compilations/sec') } ] } "@ $bytes = [System.Text.Encoding]::UTF8.GetBytes($pushdata) $ds.Dispose() $con.Close() $con.Dispose() $Body = @{ "resource"= $resourceUri "client_id" = $clientID "grant_type" = "password" "username" = $user "password" = $password } $params = @{ ContentType = "application/x-www-form-urlencoded" Headers = @{"accept"="application/json"} Body = $Body Method = "Post" URI = $TokenEndpoint } $token = Invoke-RestMethod @params $uri = [System.Uri]::EscapeUriString(("{0}/datasets/{1}/tables/LiveMonitor/rows" -f $powerBIApiUrl, $datasetid)) $ret = Invoke-WebRequest -Method Post -ContentType "application/json" -Headers @{Authorization=("Bearer {0}" -f $token.access_token)} -Uri $uri -Body $bytes
これでスクリプトによるデータセットへのデータの登録を行うことができます。
今回はマイワークスペース内のデータセットに対してデータの登録を行っていますが、Power BI ではワークスペース (アプリのワークスペース / グループ) に対してもデータセットを登録することが可能です。
ただし、Power BI Free については、アプリのワークスペースが作成できないため、ワークスペースのデータセットを登録するためには、Power BI Pro のライセンスがユーザーで REST をたたく必要があります。
ワークスペースを使用すする場合、URL が変わりますが基本的な方法は同じですね。