{"id":93579,"date":"2022-05-02T17:00:18","date_gmt":"2022-05-02T17:00:18","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=93579"},"modified":"2024-09-03T20:15:19","modified_gmt":"2024-09-03T20:15:19","slug":"template-for-automating-power-bi-refresh","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/template-for-automating-power-bi-refresh\/","title":{"rendered":"Template for automating Power BI Refresh"},"content":{"rendered":"<p>I wrote before about <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/bi-sql-server\/how-to-automate-table-level-refresh-in-power-bi\/\">Automating table Refresh in Power BI<\/a>. On that article I explained how to schedule a refresh script using the <strong>Azure Automation Account<\/strong>.<\/p>\n<p>We can improve the automation process even more. If we create a parameterized <strong>Powershell<\/strong> script and publish it to github, the script becomes available in the <strong>Automation Account<\/strong> gallery. You can use it as many times as you wish, scheduling many different administrative tasks in <strong>Power BI<\/strong> using <strong>XMLA<\/strong> scripts.<\/p>\n<p>The script will be like this one:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow: auto;width: auto;border: solid gray;border-width: .1em .1em .1em .8em;padding: .2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\" class=\"crayon:false\"><span style=\"color: #888888\">&lt;#<\/span>\r\n<span style=\"color: #dd4422\">.SYNOPSIS<\/span>\r\n<span style=\"color: #888888\">Indexes tables in a database if they have a high fragmentation<\/span>\r\n<span style=\"color: #dd4422\">.DESCRIPTION<\/span>\r\n<span style=\"color: #888888\">This runbook indexes all of the tables in a given database if the fragmentation is<\/span>\r\n<span style=\"color: #888888\">above a certain percentage.<\/span>\r\n<span style=\"color: #888888\">It highlights how to break up calls into smaller chunks,<\/span>\r\n<span style=\"color: #888888\">in this case each table in a database, and use checkpoints.<\/span>\r\n<span style=\"color: #888888\">This allows the runbook job to resume for the next chunk of work even if the<\/span>\r\n<span style=\"color: #888888\">fairshare feature of Azure Automation puts the job back into the queue every 30 minutes<\/span>\r\n<span style=\"color: #dd4422\">.PARAMETER<\/span><span style=\"color: #888888\"> PowerBIEndpoint<\/span>\r\n<span style=\"color: #888888\">Power BI XMLA endpoint address<\/span>\r\n<span style=\"color: #dd4422\">.PARAMETER<\/span><span style=\"color: #888888\"> ServicePrincipal<\/span>\r\n<span style=\"color: #888888\">Service principal to connect to the XMLA endpoint in the format Appid@TenantId<\/span>\r\n<span style=\"color: #dd4422\">.PARAMETER<\/span><span style=\"color: #888888\"> ServicePrincipalSecret<\/span>\r\n<span style=\"color: #888888\">Secret value created for the service principal<\/span>\r\n<span style=\"color: #dd4422\">.PARAMETER<\/span><span style=\"color: #888888\"> Query<\/span>\r\n<span style=\"color: #888888\">XMLA statement to be executed, either in XML or JSON.<\/span>\r\n<span style=\"color: #dd4422\">.NOTES<\/span>\r\n<span style=\"color: #888888\">AUTHOR: Dennes Torres<\/span>\r\n<span style=\"color: #888888\">LASTEDIT: March 20, 2022<\/span>\r\n<span style=\"color: #888888\">#&gt;<\/span>\r\n<span style=\"color: #008800;font-weight: bold\">param<\/span>(\r\n[<span style=\"color: #008800;font-weight: bold\">parameter<\/span>(<span style=\"color: #008800;font-weight: bold\">Mandatory<\/span>=<span style=\"color: #996633\">$True<\/span>)]\r\n<span style=\"color: #003366;font-weight: bold\">[string]<\/span> <span style=\"color: #996633\">$PowerBIEndpoint<\/span>,\r\n\r\n[<span style=\"color: #008800;font-weight: bold\">parameter<\/span>(<span style=\"color: #008800;font-weight: bold\">Mandatory<\/span>=<span style=\"color: #996633\">$True<\/span>)]\r\n<span style=\"color: #003366;font-weight: bold\">[string]<\/span> <span style=\"color: #996633\">$ServicePrincipal<\/span>,\r\n\r\n[<span style=\"color: #008800;font-weight: bold\">parameter<\/span>(<span style=\"color: #008800;font-weight: bold\">Mandatory<\/span>=<span style=\"color: #996633\">$True<\/span>)]\r\n<span style=\"color: #003366;font-weight: bold\">[string]<\/span> <span style=\"color: #996633\">$ServicePrincipalSecret<\/span>,\r\n\r\n[<span style=\"color: #008800;font-weight: bold\">parameter<\/span>(<span style=\"color: #008800;font-weight: bold\">Mandatory<\/span>=<span style=\"color: #996633\">$False<\/span>)]\r\n<span style=\"color: #003366;font-weight: bold\">[string]<\/span> <span style=\"color: #996633\">$Query<\/span>\r\n\r\n)\r\n\r\n<span style=\"color: #996633\">$assemblyPath<\/span> = <span style=\"background-color: #fff0f0\">\"C:\\Modules\\User\\Microsoft.AnalysisServices.AdomdClient\\Microsoft.AnalysisServices.AdomdClient.dll\"<\/span>\r\n<span style=\"color: #008800;font-weight: bold\">try<\/span> {<span style=\"color: #007020\">Add-Type<\/span> -Path <span style=\"color: #996633\">$assemblyPath<\/span>}\r\n<span style=\"color: #008800;font-weight: bold\">catch<\/span> { <span style=\"color: #996633\">$_<\/span>.Exception.LoaderExceptions }\r\n\r\n<span style=\"color: #996633\">$Connection<\/span> = <span style=\"color: #007020\">New-Object<\/span> Microsoft.AnalysisServices.AdomdClient.AdomdConnection\r\n<span style=\"color: #996633\">$Connection<\/span>.ConnectionString = <span style=\"background-color: #fff0f0\">\"Datasource=\"<\/span>+ <span style=\"color: #996633\">$PowerBIEndpoint<\/span> +<span style=\"background-color: #fff0f0\">\";User ID=\"<\/span>+ <span style=\"color: #996633\">$ServicePrincipal\r\n<\/span>        +<span style=\"background-color: #fff0f0\">\";Password=\"<\/span>+ <span style=\"color: #996633\">$ServicePrincipalSecret<\/span>\r\n<span style=\"color: #996633\">$Command<\/span> = <span style=\"color: #996633\">$Connection<\/span>.CreateCommand()<span style=\"color: #ff0000;background-color: #ffaaaa\">;<\/span>\r\n<span style=\"color: #996633\">$Command<\/span>.CommandTimeout = 20000<span style=\"color: #ff0000;background-color: #ffaaaa\">;<\/span>\r\n<span style=\"color: #996633\">$Command<\/span>.CommandType = <span style=\"color: #003366;font-weight: bold\">[System.Data.CommandType]<\/span><span style=\"color: #ff0000;background-color: #ffaaaa\">::<\/span>Text<span style=\"color: #ff0000;background-color: #ffaaaa\">;<\/span>\r\n<span style=\"color: #996633\">$Command<\/span>.CommandText = <span style=\"color: #996633\">$Query<\/span><span style=\"color: #ff0000;background-color: #ffaaaa\">;<\/span>\r\n<span style=\"color: #996633\">$Connection<\/span>.Open()\r\n\r\n<span style=\"color: #996633\">$Command<\/span>.ExecuteNonQuery()\r\n\r\n<span style=\"color: #996633\">$Connection<\/span>.Close()\r\n<span style=\"color: #996633\">$Connection<\/span>.Dispose()\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>You can read about how to <a href=\"https:\/\/techcommunity.microsoft.com\/t5\/azure-governance-and-management\/azure-automation-runbooks-moving-to-github\/ba-p\/2039337\">contribute to the Automation Gallery<\/a> here. I also wrote about this when I was explaining about a <a href=\"https:\/\/www.red-gate.com\/simple-talk\/blogs\/azure-sql-automation-improving-the-indexing-job\/\">script to re-index SQL Server Tables (published to the automation gallery)<\/a>.<\/p>\n<p>Let&#8217;s follow some steps to schedule the script from the gallery in an automation account.<\/p>\n<p>1) In an automation account,\u00a0 click the <em>Browse Gallery<\/em> button and search for <strong>Power BI.<\/strong>\u00a0You will find the script I published, as illustrated on the image below.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-93580\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/PBIGallery01.png\" alt=\"\" width=\"1280\" height=\"378\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>2) Click on the script and you will be able to see the entire code. You can decide if you will import it to your automation account as a runbook.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-93581\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/PBIGallery02.png\" alt=\"\" width=\"872\" height=\"720\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>3) Click on the <em>Select<\/em> button. You will need to fill the details about the new runbook which will be created.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-93582\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/PBIGallery03.png\" alt=\"\" width=\"768\" height=\"720\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>4) After clicking <em>Import<\/em> button, you can execute the runbook clicking the<em> Start<\/em> button and you will have the opportunity to fill the parameters for the powershell script, as illustrated on the screen below.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-93583\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/PBIGallery04.png\" alt=\"\" width=\"294\" height=\"720\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>5) After that, you just need to follow the execution from the job screen.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-93584\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/PBIGallery05.png\" alt=\"\" width=\"484\" height=\"579\" \/><\/p>\n<p>&nbsp;<\/p>\n<h2>Summary<\/h2>\n<p>Using the script provided in the automation gallery is even easier to automate a refresh or other administrative tasks in <strong>Power BI<\/strong> with <strong>XMLA<\/strong> scripts<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote before about Automating table Refresh in Power BI. On that article I explained how to schedule a refresh script using the Azure Automation Account. We can improve the automation process even more. If we create a parameterized Powershell script and publish it to github, the script becomes available in the Automation Account gallery&#8230;.&hellip;<\/p>\n","protected":false},"author":50808,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2,159166],"tags":[145828,145827,101611,4635],"coauthors":[6810],"class_list":["post-93579","post","type-post","status-publish","format-standard","hentry","category-blogs","category-powerbi","tag-automation-account","tag-data-refresh","tag-power-bi","tag-powershell"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93579","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/50808"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=93579"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93579\/revisions"}],"predecessor-version":[{"id":94176,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93579\/revisions\/94176"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=93579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=93579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=93579"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=93579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}