Save on Your PowerBI Embedded Capacity

Throughout this month I’ve been working on our embedded PowerBI architecture – improving performance, streamlining administration, and reducing costs. We have a small PowerBI premium capacity that allows us to serve PowerBI reports and dashboards to internal and external users in our apps without individually provisioning licensing. In PowerBI embedded documentation, this is commonly referred to as the “app owns data” architecture. In this post, I will show how Azure Automation can be used to minimize costs associated with a PowerBI premium capacity.

PowerBI embedded capacity is an incredibly powerful feature – and the price tag matches the capability. Starting at ~$750/month you can embed PowerBI into your application and for an all-you-can-eat per-user buffet (within the capacity size). That number assumes that your PowerBI embedded instance runs 24×7 – and that might not be a business requirement. Once we determined the hours that our PowerBI embedded capacity needed to be available, we automated the pause/resume of the instance.

Get Started with Azure Automation

If you’re not familiar with Azure Automation, fear not, it is a shallow learning curve.

To become familiar with Azure automation basics, follow these Azure docs quickstarts to create an automation account ( https://docs.microsoft.com/en-us/azure/automation/automation-quickstart-create-account ) and set up a sample runbook ( https://docs.microsoft.com/en-us/azure/automation/automation-quickstart-create-runbook ).

Setup Account and Required Modules

After creating a new automation account, we need to add the 2 required modules.

At this time, Az.Accounts v2 is in preview and does not support Azure Automation. There are ways to accidentally install it from the Azure Portal, which is why I provided the links above. Through those links to the PowerShell gallery you can deploy the modules right into your Azure Automation account.

Deploying PowerShell modules from PowerShell Gallery

Create and Manage a Runbook

Creating a new runbook of runbook type PowerShell Workflow
Creating a new runbook

Create a new runbook of type “PowerShell Workflow” in your Azure Automation account and click the pencil for edit in the top bar.
In the runbook editing pane, paste in the code from: https://gist.github.com/dzsquared/86abb47dc5ed7562c20566113d7e3c47 (also available below)

The workflow is controlled by 3 parameters. The first is the resource group where the PowerBI Embedded instance is located, the second is the name of the PowerBI embedded instance, and the third is whether we want to start or suspend the instance on this run. After saving and publishing our runbook, we are ready to schedule it to start and suspend our instance.

In setting up 2 schedules, it allows us to schedule both the “on” and “off”.

<p>
  Create a schedule with the <em>suspend</em> parameter as true when you would like the instance to be paused. This is likely in the evening &#8211; BUT &#8211; if you have scheduled dataset refreshes, make sure they will run while the instance is not paused.
</p>

<p>
  Create a second schedule with the <em>suspend</em> parameter as false when you would like the instance to fire back up.
</p>

<p>
  You could create more than 2 schedules, repeatedly starting and stopping your embedded capacity if your business case calls for that sort of complexity.
</p>

That’s It.

Once the schedules are enabled, you’re done. That’s all it takes to potentially be saving a huge chunk on your PowerBI embedded capacity. For our business needs, we are able to shut down the PowerBI premium instance overnight. This results in a savings of nearly 50% if we were paying for 24×7.

Here’s the PowerShell runbook script, also available here.

workflow pbi-embedded-suspend-resume
{
    Param
    (
        [Parameter(Mandatory=$true)]
        [String]
        $AzureResourceGroup,
        [Parameter(Mandatory=$true)]
        [String]
        $PowerBIEmbeddedName,
        [Parameter(Mandatory=$true)]
        [Boolean]
        $Suspend
    )
    $connectionName = "AzureRunAsConnection"

    try
    {
        # Get the connection
        $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName

        "Logging in to Azure..."
        Connect-AzAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
    }
    catch {
        if (!$servicePrincipalConnection)
        {
            $ErrorMessage = "Connection $connectionName not found."
            throw $ErrorMessage
        } else{
            Write-Error -Message $_.Exception
            throw $_.Exception
        }
    }

    #checking if the PowerBI Embedded Capacity Exisit
    $IsPBEmbExisit=Test-AzPowerBIEmbeddedCapacity -Name $PowerBIEmbeddedName

    if($IsPBEmbExisit -eq $true)
    {
        if($Suspend -eq $true )
        {
            try
            {
                #Suspending the Service
                "Suspending $PowerBIEmbeddedName started"
                $SuspendOperation = Suspend-AzPowerBIEmbeddedCapacity -Name $PowerBIEmbeddedName -ResourceGroupName $AzureResourceGroup -PassThru
                "$PowerBIEmbeddedName is Suspended Successfully"
            }
            catch
            {
                    Write-Error -Message $_.Exception
                    throw $_.Exception
            }
        }
        else
        {
            try
            {
                #Resuming the Service
                "Resuming $PowerBIEmbeddedName"
                $ResumeOperation = Resume-AzPowerBIEmbeddedCapacity -Name $PowerBIEmbeddedName -ResourceGroupName $AzureResourceGroup -PassThru
                "$PowerBIEmbeddedName Resumed Successfully "
            }
            catch
            {
                    Write-Error -Message $_.Exception
                    throw $_.Exception
            }
        }
    }

    else
    {
        "The Provided Resource $PowerBIEmbeddedName doesnot exist"
    }
}