Automating Power BI Refresh Performance with PowerShell and SQL Server

PBI Workspace Metadata to SQL Server

Posted by Ted on November 15, 2023

Automating Power BI Refresh Performance Data Collection and Analysis with PowerShell and SQL Server

Power BI is a powerful business intelligence tool that allows organizations to visualize and analyze their data. One critical aspect of maintaining a healthy Power BI environment is monitoring and analyzing the performance of dataset refreshes. In this article, we will explore a PowerShell script designed to automate the collection of Power BI refresh performance data and store it in a SQL Server database for further analysis.

Script Overview

The PowerShell script provided here serves the purpose of collecting and storing Power BI refresh performance data. Let’s break down its key components and functionality:

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<#
.SYNOPSIS
    PowerShell script for collecting and storing Power BI refresh 
    Performance data into a SQL Server database.

.DESCRIPTION
    This script connects to the Power BI service, retrieves workspace, 
    report, and dataset information, and captures refresh history details.
    The collected data is then stored in a SQL Server database table 
    for analysis and reporting.

#>

param (
    [string]$sqlUsername = "SuperAdmin",            # SQL Server username
    [string]$sqlPassword = "**********",            # SQL Server password
    [string]$serverName = "DESKTOP-*******",       # SQL Server instance 46A7LA5
    [string]$databaseName = "PBI_Inventory",       # Database name
    [bool]$clearOldData = $false                    # Flag to determine whether to clear old data
)

# Function to install or update a PowerShell module
function Install-OrUpdate-Module([string]$ModuleName) {
    $module = Get-Module $ModuleName -ListAvailable -ErrorAction SilentlyContinue

    if (!$module -or ($module.Version -ne '1.0.0' -and $module.Version -le '1.0.410')) {
        $action = if (!$module) { "Installing" } else { "Updating" }
        Write-Host "$action module $ModuleName ..."
        Install-Module -Name $ModuleName -Force -Scope CurrentUser
        Write-Host "Module $ModuleName $action complete"
    }
}

# Function to execute a SQL command with parameters
function Execute-DB-Command-With-Params([System.Data.SqlClient.SqlConnection]$connection, [String]$command, [Hashtable]$parameters) {
    $cmd = $connection.CreateCommand()
    $cmd.CommandText = $command
    foreach ($key in $parameters.Keys) {
        $cmd.Parameters.AddWithValue($key, $parameters[$key]) | Out-Null
    }
    $cmd.ExecuteNonQuery()
}

# Function to add a table to the database
function Add-Table([System.Data.SqlClient.SqlConnection]$connection, [String]$tableName, [String[]]$feature) {
    $createTableScript = @"
        IF OBJECT_ID('$tableName', 'U') IS NOT NULL
            DROP TABLE $tableName;
        CREATE TABLE $tableName (
            $($feature -join " VARCHAR(MAX),`n")
            VARCHAR(MAX)
        );
        ALTER TABLE $tableName
            ADD InsertDataTime VARCHAR(MAX);
"@
    Execute-DB-Command-With-Params $connection $createTableScript @{}
}

# Function to insert data into a table
function Insert-Data([System.Data.SqlClient.SqlConnection]$connection, [String]$tableName, [String[]]$feature, [String[]]$insertData) {
    $today = Get-Date -Format "yyyy-MM-dd_HH:mm:ss"
    $columns = $feature -join " VARCHAR(MAX),`n"

    $createQuery = @"
    IF OBJECT_ID('$tableName', 'U') IS NULL
    BEGIN
        CREATE TABLE $tableName (
            $columns VARCHAR(MAX),
            InsertDataTime VARCHAR(MAX)
        );
    END
"@

    $insertQuery = @"
    INSERT INTO $tableName ($($feature -join ', '), InsertDataTime)
    VALUES ('$($insertData -join "', '")', '$($today)');
"@

    $combinedScript = $createQuery + $insertQuery
    Execute-DB-Command-With-Params $connection $combinedScript @{}
}

# Install or update the required PowerShell module for Power BI management
Install-OrUpdate-Module -ModuleName "MicrosoftPowerBIMgmt"
Connect-PowerBIServiceAccount

# Set up the SQL Server connection
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = "Data Source=$serverName;Initial Catalog=$databaseName;User Id=$sqlUsername;Password=$sqlPassword;"
$connection.Open()

# Define Power BI table and features
$tableName_PBI_Performance = "dbo.PBI_Performance"
$feature_PBI_Performance = @("Workspace", "Report", "Dataset", "StartTime", "EndTime", "Status", "WorkspaceId", "ReportId", "DatasetId", "CreationTime","LastTimeRefresh","RefreshCostTime")

# Create table if clearOldData flag is set
if ($clearOldData) {
    Add-Table $connection $tableName_PBI_Performance $feature_PBI_Performance
}

# Process Power BI workspaces and refresh history
ForEach ($workspace in (Get-PowerBIWorkspace)) {
    $workspaceId = $workspace.Id
    $WorkspaceName = $workspace.Name

    foreach ($report in (Get-PowerBIReport -WorkspaceId $workspaceId)) {
        $ReportId = $report.Id
        $ReportName = $report.Name

        foreach ($dataset in (Get-PowerBIDataset -Id $report.DatasetId -WorkspaceId $workspaceId)) {
            $DatasetName = $dataset.Name
            Write-Host $DatasetName

            $DatasetId = $dataset.Id
            $refreshUri = "groups/$workspaceId/datasets/$($dataset.Id)/refreshes"
            $refreshHistory = Invoke-PowerBIRestMethod -Url $refreshUri -Method Get | ConvertFrom-Json
            $CreateTime = $refreshHistory.value[0].StartTime
            $LastTimeRefresh = $refreshHistory.value[$refreshHistory.value.Length-1].EndTime

            foreach ($refreshEntry in $refreshHistory.value) {
                $Status = $refreshEntry.Status
                $startTime = [DateTime]::Parse($refreshEntry.StartTime)
                $endTime = [DateTime]::Parse($refreshEntry.EndTime)
                $timeDifferenceInSeconds = [math]::Round(($endTime - $startTime).TotalSeconds)
                $formattedTimeDifference = "$($timeDifferenceInSeconds)s"
                
                $data_PBI_Performance = @($WorkspaceName, $ReportName, $DatasetName, $refreshEntry.StartTime, $refreshEntry.EndTime, $Status, $workspaceId, $ReportId, $DatasetId, $CreateTime, $LastTimeRefresh, $formattedTimeDifference)
                Insert-Data $connection $tableName_PBI_Performance $feature_PBI_Performance $data_PBI_Performance
            }
        }
    }
}

# Close the database connection
$connection.Close()

Write-Host "Completed"

Parameters

The script utilizes parameters to allow customization of the SQL Server connection details and control whether old data should be cleared before inserting new data. These parameters include SQL Server credentials, server name, database name, and a flag for clearing old data.

Module Installation

The script checks for the presence of the required PowerShell module, MicrosoftPowerBIMgmt, and either installs or updates it if necessary. This module is essential for interacting with the Power BI service.

SQL Server Connection

The script establishes a connection to a SQL Server database using the provided credentials. It then defines functions for executing SQL commands and managing the database tables.

Power BI Performance Table

The script defines a table structure ($tableName_PBI_performance) and features ($feature_PBI_performance) to store Power BI refresh performance data. It includes workspace, report, and dataset information, along with details like start time, end time, status, and refresh duration.

Main Processing Loop

The script iterates through Power BI workspaces, reports, and datasets, querying refresh history details for each dataset. It calculates refresh duration and formats the data for insertion into the SQL Server table.

Data Insertion

The script uses functions to create the table if the clearOldData flag is set and inserts the collected data into the SQL Server table.

Conclusion

After processing all Power BI workspaces, reports, and datasets, the script closes the database connection and concludes. The result is a SQL Server table populated with valuable Power BI refresh performance data.

Conclusion

Automating the collection of Power BI refresh performance data is crucial for monitoring the health of your Power BI environment. This PowerShell script provides a scalable and efficient solution to gather, store, and analyze refresh performance data in a SQL Server database. By leveraging the Power BI management module and SQL Server connectivity, organizations can gain insights into refresh trends, identify potential issues, and make informed decisions to optimize their Power BI workflows.