Fabric101e3_PausingAndScaling_00

Microsoft Fabric 101 Episode 3: Pausing and Scaling using portal and Powershell

Welcome to Microsoft Fabric 101 series – your comprehensive guide to mastering Microsoft Fabric. This series of articles and videos is designed to help you understand and effectively use Microsoft Fabric, whether you’re a beginner or looking to deepen your knowledge. We’ll cover everything from the basics of setting up and configuring your Fabric tenant to advanced features and best practices.

Prerequisite articles:

Series:

YT: link
Blog: link
Let’s get started on this exciting journey!

In today’s episode, we’ll discuss scaling and pausing/resuming Fabric capacity. Choosing a specific SKU doesn’t mean you’re stuck with it forever.

Introduction

Before we begin, here are a few important facts to know:

  • Consider using Reservations to save money (link) especially if your capacity will be active most of the time.
  • All described operations apply to FSKU, not PSKU (Power BI Premium).
  • When pausing capacity, any remaining cumulative overages and smoothed operations are summed and added to your Azure bill.

You can always pause Fabric capacity when it’s not in use or scale it up or down according to your needs. This can be done easily via the Azure portal using the graphical interface. Simply select the appropriate capacity and click one of the available buttons at the top:

A similar experience applies to scaling, where you can select the appropriate SKU from the list. Scaling to an SKU below F64 typically takes just a few seconds, while higher levels may take longer.

It’s simple, isn’t it? But can we automate this operation? Yes, we can—and in most cases, we want to.

Automation

App registration

For automation, we typically create a dedicated credential, such as a service principal, to run all the code because it offers several benefits:

  • It’s not tied to any individual.
  • It’s managed by Microsoft Entra.
  • It provides a secure way to handle credentials and permissions.
  • It enables fine-grained access control to resources.

To create it, go to the Azure portal and search for App registrations, as shown in the image below:

Then, click on New registration:

Registering the application in our case is straightforward. Simply give it a meaningful name. The other options aren’t relevant for us, so you can leave them at their default settings and click Register.

After a few seconds, the app will be registered, along with the Service Principal associated with it. The most important details can be found on the Overview page, where you’ll see the Application (client) ID and Directory (tenant) ID—both of which will be useful later. We also need to assign a secret value that we’ll use in our script. To do this, select Certificates & secrets.

Click New client secret and specify an expiration date that aligns with your company policy. Provide a descriptive name for the secret to indicate its purpose, as an app or service principal may have multiple secrets used for different purposes.

Our service principal is ready, so now we need to assign it the appropriate permissions. To perform operations like scaling, the credential must be added as a capacity or fabric administrator. In the Azure portal, select the capacity, then go to the Capacity administrators tab where you can add the previously created Service Principal.

To pause and resume the capacity, the service principal must have the following granular permissions:

  • Microsoft.Fabric/capacities/read
  • Microsoft.Fabric/capacities/write
  • Microsoft.Fabric/suspend/action
  • Microsoft.Fabric/resume/action

If you prefer a less specific approach, you can assign the service principal the Contributor built-in role on the fabric capacity resource.

Script

Now, let’s write our PowerShell script. Keep in mind that this is just one method; you can also use Logic Apps, Python, or any other approach you prefer.

In our scenario, we need to provide basic information such as tenant ID, client ID, and client secret. I’ll store these in variables. While it’s best practice to use a secure store like Key Vault for secrets (rather than keeping them in clear text), I’ll use clear text here for simplicity and visibility.

I also included an operation variable with three possible values:

  • resume
  • suspend
  • scale

This way, one script can handle all operations. Additionally, there are two more variables: sku, which specifies the Fabric SKU for scaling (not used for operations other than scale), and uri, which contains the base URI for sending requests.

 

$tenantId = "deca7fb5-bee9-4134-9d26-e222fb2fe976"
$clientId = "5e789679-d979-4def-86f7-ae238c82f2c2"
$clientSecret = "xyz"
$operation = "resume"
$sku = "F4"

$uri = "https://management.azure.com/subscriptions/f6996f9a-a352-4b64-8ab1-865c9f9c4c9b/resourceGroups/rg-fabric-demos/providers/Microsoft.Fabric/capacities/fabcapacityseequality01"

The next section of the script is designed to obtain an OAuth 2.0 access token from Azure Active Directory (AAD)/Entra using client credentials, and then prepare the headers for a subsequent API request.

The first step is to define the Request Body:

$body = @{
    grant_type    = "client_credentials"
    client_id     = $clientId
    client_secret = $clientSecret
    resource      = "https://management.azure.com/"
}

Here, we create a hashtable $body containing the necessary parameters for the OAuth 2.0 token request:

  • grant_type: Specifies the type of OAuth 2.0 grant. In this case, it is set to "client_credentials".
  • client_id: The client ID of the application requesting the token.
  • client_secret: The client secret associated with the application.
  • resource: The resource for which the token is requested, in this case, the Azure Management API.

Next, we will attempt to obtain the access token:

try {
    $tokenResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -ContentType "application/x-www-form-urlencoded" -Body $body
    $accessToken = $tokenResponse.access_token

This code attempts to obtain an access token by making a POST request to the Azure AD token endpoint:

  • Invoke-RestMethod is used to send the request.
  • The response, $tokenResponse, is expected to contain the access token in the access_token field.
  • The access token is then extracted and stored in the $accessToken variable.

Next, we need to prepare the header for our request:

# Headers for the PATCH request
$headers = @{
    Authorization = "Bearer $accessToken"
    "Content-Type" = "application/json"
}

 

The Authorization header is set to "Bearer $accessToken", where $accessToken is the token obtained in the previous step. The Content-Type header is set to "application/json", indicating that the request body will be in JSON format.

Next, a switch statement handles different operations (scale, resume, suspend) based on the value of the $operation variable.

Scale operation

"scale" {
    $uri = $uri+"?api-version=2023-11-01"
    $method = "Patch"
    $body = @{
        properties = @{
            administration = @{
                # Add your administration properties here
            }
        }
        sku = @{
            name = $sku
            tier = "Fabric"
        }
        tags = @{
            # Add your resource tags here
        }
    } | ConvertTo-Json
}
  • URI: Appends the API version query parameter to the $uri.
  • Method: Sets the HTTP method to Patch.
  • Body: Constructs a JSON body with properties, sku, and tags. The body is then converted to JSON format using ConvertTo-Json.
    • properties: Contains an administration object where additional properties can be added.
    • sku: Specifies the SKU name and tier, with the tier set to "Fabric".
    • tags: Placeholder for resource tags.

Resume operation:

"resume" {
    $uri = $uri + "/resume?api-version=2023-11-01"
    Write-Output $uri
    $method = "Post"
    $body = $null
}
  • URI: Appends /resume and the API version query parameter to the $uri.
  • Output: Prints the modified URI to the output.
  • Method: Sets the HTTP method to Post.
  • Body: Sets the body to null, as no body is required for this operation.

Suspend operation:

"suspend" {
    $uri = $uri + "/suspend?api-version=2023-11-01"
    Write-Output $uri
    $method = "Post"
    $body = $null
}
  • URI: Appends /suspend and the API version query parameter to the $uri.
  • Output: Prints the modified URI to the output.
  • Method: Sets the HTTP method to Post.
  • Body: Sets the body to null, as no body is required for this operation.

Invoke the API

$response = Invoke-RestMethod -Method $method -Uri $uri -Headers $headers -Body $body

The Invoke-RestMethod cmdlet is used to make the HTTP request. The method (such as GET or POST), URI, headers, and body of the request are passed as parameters.

if ($response) {
    $response
} else {
    Write-Output "No content returned in the response."
}

This block checks if the $response variable contains any data. If $response is not null, it outputs the response. If $response is null, it outputs a message indicating that no content was returned.

catch {
    Write-Error "An error occurred: $_"
}

This catch block handles any exceptions that occur during the API call. If an error occurs, it writes an error message to the output, including the error details ($_).

Below, you can see that the script works as expected:

Below you can find entire script and video, I hope you find it useful.

$tenantId = "deca7fa5-1111-2222-9d26-eb2fe976"
$clientId = "5e876669-d979-4def-86f7-ae238f2c2"
$clientSecret = "secret"
$operation = "resume"
$sku = "F4"

$uri = "https://management.azure.com/subscriptions/f6996f9a-a352-4b64-8ab1-865c9f9c4c9b/resourceGroups/rg-fabric-demos/providers/Microsoft.Fabric/capacities/fabcapacityseequality01"

# Authenticate using the service principal
$body = @{
    grant_type    = "client_credentials"
    client_id     = $clientId
    client_secret = $clientSecret
    resource      = "https://management.azure.com/"
}
try {
$tokenResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -ContentType "application/x-www-form-urlencoded" -Body $body
$accessToken = $tokenResponse.access_token

# Headers for the PATCH request
$headers = @{
    Authorization = "Bearer $accessToken"
    "Content-Type" = "application/json"
}

    # Determine the URI and method based on the operation
    switch ($operation) {
        "scale" {
            $uri = $uri+"?api-version=2023-11-01"
            $method = "Patch"
            $body = @{
                properties = @{
                    administration = @{
                        # Add your administration properties here
                    }
                }
                sku = @{
                    name = $sku
                    tier = "Fabric"
                }
                tags = @{
                    # Add your resource tags here
                }
            } | ConvertTo-Json
        }
        "resume" {
            $uri = $uri + "/resume?api-version=2023-11-01"
            Write-Output $uri
            $method = "Post"
            $body = $null
        }
        "suspend" {
            $uri = $uri + "/suspend?api-version=2023-11-01"
            Write-Output $uri
            $method = "Post"
            $body = $null
        }
        default {
            throw "Invalid operation: $operation"
        }
    }

    # Invoke the API with the determined method and URI
    $response = Invoke-RestMethod -Method $method -Uri $uri -Headers $headers -Body $body

    # Output the response
    if ($response) {
        $response
    } else {
        Write-Output "No content returned in the response."
    }
}
catch {
    Write-Error "An error occurred: $_"
}

 

Leave a Reply