
Power BI admin dashboard
Suzanne van Es, februari 2023
Voor onze klant was collega Peter Coenen op zoek naar stuurinformatie voor het beheer van Power BI-licenties. De rapporten die standaard worden aangeboden door Microsoft sloten niet goed aan bij de vraag die er lag. Na wat nader onderzoek bleek dat er veel informatie wordt bijgehouden en prima bruikbaar is als je bereid bent zelf wat in te richten. Laat dat nou net onze specialisatie zijn; data bruikbaar maken voor het beantwoorden van businessvragen. Dus ging Peter aan de slag met data die wordt aangeboden via de API’s van Microsoft en heeft hij zijn eigen dashboard gebouwd. In onderstaand interview lees je waar Peter initieel tegenaan liep, hoe hij tot een oplossing is gekomen en geeft hij een aantal tips als je hiermee ook zelf aan de slag wilt.

Waarom zijn jullie een eigen dashboard gaan bouwen? Is er geen standaard dashboard beschikbaar?
Door Microsoft wordt er van alles standaard aangeboden. Echter, deze standaard dashboards sloten niet aan bij de vragen die onze stakeholders hadden. Zij wilden besparen op licentiekosten. De meest voor de hand liggende actie is om het aantal uitgegeven licenties te verminderen door de niet gebruikte licenties te elimineren. Maar, ook switchen naar een ander licentiemodel is een optie, dit vereist wel een goed inzicht in de hoeveelheid actieve gebruikers.
Microsoft biedt standaard het “Usage Matrix Report” aan. Dit rapport laat het gebruik van Power BI zien per workspace. Echter, onze klant heeft inmiddels 40 workspaces en gebruikers zitten vaak in meerdere workspaces. Om te bepalen of iemand Power BI niet meer gebruikt moet je 40 overzichten controleren, dat is niet te doen.
Ook bevat het “Usage Matrix Report” niet alle informatie. Standaard kan je 30 dagen terugkijken, maar wat als iemand werkzaam is in een kwartaal proces en dus maar 1 keer per kwartaal zijn rapportages raadpleegt. Die wil je niet zijn Power BI licentie ontnemen. Een andere tekortkoming van het rapport is dat je alleen kan zien hoe vaak een rapport wordt geopend. Een “subscription” telt ook als “rapport geopend” maar dat wil niet zeggen dat het rapport ook daadwerkelijk gebruikt wordt. Het “Usage Matrix Report” was voor ons dus onbruikbaar voor licentiemanagemen
Welke inzichten geeft jullie dashboard?
Op dit moment laat ons dashboard zien hoe vaak een rapport daadwerkelijk wordt gebruikt en door welke gebruiker. Hierbij kijken we naar de volgende acties: “rapport verversen”, “rapport openen” of “downloaden” en het “extern aanroepen van een dataset”. Er is een lange lijst met acties beschikbaar waaruit je kan kiezen. En we meten ook of mensen “subscriptions” hebben lopen. Dit doen we over alle workspaces heen.
Het mooie is dat we met deze informatie verschillende vraagstukken kunnen beantwoorden. Het biedt natuurlijk inzicht in welke gebruikers geen rapporten meer gebruiken maar het geeft ook veel informatie over hoe een rapport wordt gebruikt. Juist dit inzicht zegt veel over de kwaliteit van een specifiek rapport. Deze informatie is nodig als je aan de slag wilt met “Report Lifecycle Management”, een tweede behoefte die er lag. Als we zien dat een rapport alleen maar wordt gedownload naar Excel of dat er altijd maar één pagina wordt bekeken, is dat een signaal om het gesprek met gebruikers aan te gaan. Vaak weten gebruikers niet wat de mogelijkheden zijn van Power BI en door het gesprek aan te gaan proberen we het rapport beter te laten aansluiten bij de behoeftes die er zijn.
Een ander inzicht wat vanuit beheer heel waardevol is, is het gebruik over de dag. We zien bijvoorbeeld dat het in de ochtend altijd heel druk is in Power BI. Met deze kennis kunnen we de beschikbare capaciteit veel beter managen door bijvoorbeeld in de ochtend de capaciteit op te schalen.
Ook passen we het load schedule hierop aan en verversen we de datasets op momenten dat het rustig is op de server.


Jullie gebruiken een API om data op te halen voor het dashboard, kan je daar wat meer over vertellen?
Microsoft biedt voor Power BI ongeveer 100 verschillende API’s aan. Een deel hiervan levert data over het gebruik van Power BI, andere voeren specifieke acties uit. Het was een hele zoektocht om in dit grote aanbod de juiste te vinden voor ons dashboard. Wij hebben er uiteindelijk voor gekozen de volgende API’s te gebruiken:
- Workspaces: https://api.powerbi.com/v1.0/myorg/admin/groups
- Apps: https://api.powerbi.com/v1.0/myorg/admin/apps
- Refreshables: https://api.powerbi.com/v1.0/myorg/admin/capacities/refreshables
Wat je goed in de gaten moet houden is dat de API’s op verschillend granulariteitsniveau de data aanbieden. Je moet dus van tevoren goed nadenken over je datamodel. Users zijn bijvoorbeeld beschikbaar bij verschillende componenten zoals workspaces, datasets en apps. Je moet beslissen op welk niveau je wilt gaan rapporteren zodat je de juiste keuzes kan maken. Dat er zoveel beschikbaar is maakt het natuurlijk ook wel heel flexibel en er komen telkens weer nieuwe API’s bij. Het is nog echt een model dat in ontwikkeling is bij Microsoft.
Welke uitdagingen zijn jullie tegengekomen bij de bouw van het dashboard?
Op dit moment laden we de API’s nog rechtstreeks in de dataset in Power BI. De API beschermt je tegen een overload door maximaal 1000 regels per keer aan te bieden, dit is onder andere het geval bij de API voor activiteiten. Zijn er meer dan 1000 activiteiten in de set dan krijg je ook een token meegeleverd. Met deze token kan je de resterende regels ophalen. Daarnaast is er ook een begrenzing op tijd, je kan alleen activiteiten opvragen van het laatste uur. Als je dus data over 30 dagen wilt binnen halen dan moet je minimaal 720 keer de API aanroepen. Om dit goed te managen hebben we een loop gebouwd zodat dit nu automatisch gaat. In het onderstaande blok zie je hoe we dit hebben gedaan:
Codeblok Loop
(accessToken as text, optional startDate as text, optional endDate as text, optional continuationToken as text, optional loop as number, optional data as list) => let Source = Json.Document(Web.Contents("https://api.powerbi.com/v1.0/myorg/", [ RelativePath=if loop = 0 then "admin/activityevents?startDateTime=" & startDate & "&endDateTime=" & endDate else "admin/activityevents?continuationToken='" & continuationToken & "'", Headers=[Authorization="Bearer " & #"GET Access Token"()] ] )), token = Source[continuationToken], currentData = Source[activityEventEntities], appendedData = List.Combine({data, currentData}), loopNum = loop + 1, output = if token is null or loopNum > 100 then appendedData else @#"GET Activity"(accessToken, "", "", token, loopNum, appendedData) in output
Codeblok Activity
let Source = List.Dates, #"Invoked FunctionSource" = Source(Date.AddDays(DateTime.Date(DateTime.FixedLocalNow()), -30), 30, #duration(1, 0, 0, 0)), #"Converted to Table" = Table.FromList(#"Invoked FunctionSource", Splitter.SplitByNothing(), null, null, ExtraValues.Error), #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "Date"}}), #"Added Custom" = Table.AddColumn(#"Renamed Columns", "StartDate", each "'" & Date.ToText([Date], "YYYY-MM-DD") & "T00:00:00" & "'"), #"Added Custom1" = Table.AddColumn(#"Added Custom", "EndDate", each "'" & Date.ToText([Date], "YYYY-MM-DD") & "T23:59:59" & "'"), #"Invoked Custom Function" = Table.AddColumn(#"Added Custom1", "GetActivity", each #"GET Activity"(#"GET Access Token"(), [StartDate], [EndDate], null, 0, {})), #"Expanded GetActivity" = Table.ExpandListColumn(#"Invoked Custom Function", "GetActivity"), #"Expanded GetActivity1" = Table.ExpandRecordColumn(#"Expanded GetActivity", "GetActivity", {"Id", "RecordType", "CreationTime", "Operation", "OrganizationId", "UserType", "UserKey", "Workload", "UserId", "ClientIP", "Activity", "ItemName", "WorkSpaceName", "DatasetName", "ReportName", "CapacityId", "CapacityName", "WorkspaceId", "ObjectId", "DatasetId", "ReportId", "EmbedTokenId", "ArtifactId", "ArtifactName", "IsSuccess", "ReportType", "RequestId", "ActivityId", "DistributionMethod", "ConsumptionMethod", "ArtifactKind"}, {"GetActivity.Id", "GetActivity.RecordType", "GetActivity.CreationTime", "GetActivity.Operation", "GetActivity.OrganizationId", "GetActivity.UserType", "GetActivity.UserKey", "GetActivity.Workload", "GetActivity.UserId", "GetActivity.ClientIP", "GetActivity.Activity", "GetActivity.ItemName", "GetActivity.WorkSpaceName", "GetActivity.DatasetName", "GetActivity.ReportName", "GetActivity.CapacityId", "GetActivity.CapacityName", "GetActivity.WorkspaceId", "GetActivity.ObjectId", "GetActivity.DatasetId", "GetActivity.ReportId", "GetActivity.EmbedTokenId", "GetActivity.ArtifactId", "GetActivity.ArtifactName", "GetActivity.IsSuccess", "GetActivity.ReportType", "GetActivity.RequestId", "GetActivity.ActivityId", "GetActivity.DistributionMethod", "GetActivity.ConsumptionMethod", "GetActivity.ArtifactKind"}), #"Changed Type" = Table.TransformColumnTypes(#"Expanded GetActivity1",{{"Date", type date}}) in #"Changed Type"
Wat zouden jullie nog meer willen toevoegen?
We zijn dit traject begonnen met het idee dat we de API’s direct als bron in Power BI wilden gebruiken. We zijn daar toch op teruggekomen. De behoefte om meer dan 30 dagen aan historie beschikbaar te hebben is nog niet opgelost in deze opzet. Als we de data elke dag gaan laden in een historisch data archief (HDA) dan bouwen we deze historie wel op. Bovendien gaan we dan ook een stuk efficiënter om met het laden van de activiteiten data. Een ander voordeel van deze ontkoppeling is dat we zelf het rapportagemodel (stermodel) voor Power BI kunnen neerzetten en het hiermee een stuk overzichtelijk, en dus minder foutgevoelig kunnen maken.
We zouden ook nog graag een licentieoverzicht willen toevoegen aan het dashboard. Iemand kan een licentie voor Power BI hebben zonder dat hij een user is. Deze gebruikers zijn nu niet inzichtelijk in het dashboard.
Ook zouden we graag de actie gerelateerde API’s gaan inzetten. Als we nu bijvoorbeeld een user willen verwijderen dan moet dit handmatig per workspace worden gedaan. Als we de API hiervoor zouden gebruiken kan dit met 1 druk op de knop. Hetzelfde geldt natuurlijk voor het toevoegen van users.
Heb je nog tips voor andere mensen die ook een vergelijkbaar dashboard willen bouwen?
Zoek van tevoren goed uit wat je wilt en wat er mogelijk is. Bekijk de lijst met API’s aandachtig zodat je goed weet wat er beschikbaar is en probeer dingen uit voordat je gaat bouwen. Er is enorm veel beschikbaar, het kan je veel tijd besparen als je op voorhand al een goed beeld hebt over wat je wilt realiseren.