Azure SQL Database scheduled autoscaling

Posted by

One of the major benefits of Azure is scalability, the cloud has been built to be elastic to be as cost-effective as possible. Azure solutions can be scaled in ways that would never be possible with your own hardware. You are able to scale up and out when the demand arises, and, more importantly, you can scale down and in when you don’t need all the resources anymore, thereby saving a lot of money.

Autoscaling based on a schedule allows you to scale your solution according to predictable resource demand. For example you could require the highest capacity on Monday during peak hours, while the rest of the week the traffic is decreased allowing you to scale down. Outside business hours and during weekends you could then scale down further to the absolute minimum.

Azure SQL Database currently offers four service tiers: Basic, Standard and Premium. Databases are isolated from each other and portable. You can change between tiers easily and without downtime.
Azure SQL database tiers and performance levels


Scheduled autoscaling with Azure Automation

To automate scaling of Azure SQL Databases based on a schedule I have created an Azure Automation PowerShell Runbook called AzureSQLDatabaseScheduledAutoScaling. You can easily import this runbook into your Azure Automation account and then execute it against your database by entering values for a few parameters that specify your database details, your Automaton Run As Account and a database-specific scaling schedule. A step-by-step guide can be found at the bottom of this post.

Scheduling of the runbook itself can be done by creating a recurring hourly Automation Schedule. A single runbook can have multiple jobs running at one time. This means it is possible to create multiple schedules for the AzureSQLDatabaseScheduledAutoScaling runbook, enabling scaling of multiple databases simultaneously.

Scaling of the database will only be performed in case the runbook execution moment matches a day/time slot specified in the scaling schedule parameter. If the runbook executes and the database is in the desired edition/tier already, no work will be done. Don’t worry about the costs of Azure Automation, the first 500 run minutes are free and after that you pay €0.002 / minute (as per November 2018).

Azure Automation Runbook Architecture

When you start using this solution, keep the following in mind:

  • The length of time for a switch of edition/tier varies, but is generally under 4 seconds, and under 30 seconds in 99% of the time. The duration of the entire scale process depends on both the size and service tier of the database before and after the change. For example a 250 GB database that is changing to, from, or within a Standard service tier, should complete within 6 hours. For a database of the same size that is changing performance levels within the Premium service tier, it should complete within 3 hours.
  • Behind the scenes, changing the edition/tier of a database creates a replica of the original database at the new edition/tier, and then switches connections over to the replica. No data is lost during this process. During the switch over to the replica, connections to the database are disabled, so some transactions in flight may be rolled back. If there are large numbers of transactions in flight at the moment connections are disabled, the length of time for the switch over may be longer.
  • To scale a database down, the database must be smaller than the maximum allowed size of the target service tier.
  • Objects that are not supported in target tiers can become inaccessible. For example when you scale down a Premium database that contains clustered columnstore indexes to Standard or Basic, the tables will be inaccessible until you scale back to Premium again.

The Runbook PowerShell script

The PowerShell script below can be used in an Azure Automation Runbook with type “PowerShell”.

The script contains the following logic:

  1. Authenticate with Azure Automation Run As account.
  2. Get the current day of week and current time, and convert it to the time zone that is specified.
  3. Check which of the specified ‘slots’ in the scaling schedule is currently active.
  4. Scale database to edition/tier that is specified in the scaling schedule.
    If no schedule for the current day/time is found, scale to default edition/tier.
    If database is already in target edition/tier, do nothing.

.SYNOPSIS
Vertically scale an Azure SQL Database up or down according to a
schedule using Azure Automation.

.DESCRIPTION
This Azure Automation runbook enables vertically scaling of
an Azure SQL Database according to a schedule. Autoscaling based
on a schedule allows you to scale your solution according to
predictable resource demand. For example you could require a
high capacity (e.g. P2) on Monday during peak hours, while the rest
of the week the traffic is decreased allowing you to scale down
(e.g. P1). Outside business hours and during weekends you could then
scale down further to a minimum (e.g. S0). This runbook
can be scheduled to run hourly. The code checks the
scalingSchedule parameter to decide if scaling needs to be
executed, or if the database is in the desired state already and
no work needs to be done. The script is Timezone aware.

.PARAMETER environmentName
Name of Azure Cloud environment. Default is AzureCloud, only change
when on Azure Government Cloud, for example AzureUSGovernment.

.PARAMETER resourceGroupName
Name of the resource group to which the database server is
assigned.

.PARAMETER azureRunAsConnectionName
Azure Automation Run As account name. Needs to be able to access
the $serverName.

.PARAMETER serverName
Azure SQL Database server name.

.PARAMETER databaseName
Azure SQL Database name (case sensitive).

.PARAMETER scalingSchedule
Database Scaling Schedule. It is possible to enter multiple
comma separated schedules: [{},{}]
Weekdays start at 0 (sunday) and end at 6 (saturday).
If the script is executed outside the scaling schedule time slots
that you defined, the defaut edition/tier (see below) will be
configured.

.PARAMETER scalingScheduleTimeZone
Time Zone of time slots in $scalingSchedule.
Available time zones: [System.TimeZoneInfo]::GetSystemTimeZones().

.PARAMETER defaultEdition
Azure SQL Database Edition that will be used outside the slots
specified in the scalingSchedule paramater value.
Available values: Basic, Standard, Premium.

.PARAMETER defaultTier
Azure SQL Database Tier that will be used outside the slots
specified in the scalingSchedule paramater value.
Example values: Basic, S0, S1, S2, S3, P1, P2, P4, P6, P11, P15.

.EXAMPLE
-environmentName AzureCloud
-resourceGroupName myResourceGroup
-azureRunAsConnectionName AzureRunAsConnection
-serverName myserver
-databaseName myDatabase
-scalingSchedule [{WeekDays:[1], StartTime:”06:59:59″, StopTime:”17:59:59″, Edition: “Premium”, Tier: “P2″}, {WeekDays:[2,3,4,5], StartTime:”06:59:59″, StopTime:”17:59:59”, Edition: “Premium”, Tier: “P1”}]
-scalingScheduleTimeZone W. Europe Standard Time
-defaultEdition Standard
-defaultTier S0

.NOTES
Author: Jorg Klein
Last Update: Nov 2018

param(
[parameter(Mandatory=$false)]
[string] $environmentName = "AzureCloud",   

[parameter(Mandatory=$true)]
[string] $resourceGroupName,

[parameter(Mandatory=$false)]
[string] $azureRunAsConnectionName = "AzureRunAsConnection",

[parameter(Mandatory=$true)]
[string] $serverName,

[parameter(Mandatory=$true)]
[string] $databaseName,

[parameter(Mandatory=$true)]
[string] $scalingSchedule,

[parameter(Mandatory=$false)]
[string] $scalingScheduleTimeZone = "W. Europe Standard Time",

[parameter(Mandatory=$false)]
[string] $defaultEdition = "Standard",

[parameter(Mandatory=$false)]
[string] $defaultTier = "S0"
)

filter timestamp {"[$(Get-Date -Format G)]: $_"}

Write-Output "Script started." | timestamp

$VerbosePreference = "Continue"
$ErrorActionPreference = "Stop"

#Authenticate with Azure Automation Run As account (service principal)
$runAsConnectionProfile = Get-AutomationConnection -Name $azureRunAsConnectionName
$environment = Get-AzureRmEnvironment -Name $environmentName
Add-AzureRmAccount -Environment $environment -ServicePrincipal `
-TenantId $runAsConnectionProfile.TenantId `
-ApplicationId $runAsConnectionProfile.ApplicationId `
-CertificateThumbprint ` $runAsConnectionProfile.CertificateThumbprint | Out-Null
Write-Output "Authenticated with Automation Run As Account."  | timestamp

#Get current date/time and convert to $scalingScheduleTimeZone
$stateConfig = $scalingSchedule | ConvertFrom-Json
$startTime = Get-Date
Write-Output "Azure Automation local time: $startTime." | timestamp
$toTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById($scalingScheduleTimeZone)
Write-Output "Time zone to convert to: $toTimeZone." | timestamp
$newTime = [System.TimeZoneInfo]::ConvertTime($startTime, $toTimeZone)
Write-Output "Converted time: $newTime." | timestamp
$startTime = $newTime

#Get current day of week, based on converted start time
$currentDayOfWeek = [Int]($startTime).DayOfWeek
Write-Output "Current day of week: $currentDayOfWeek." | timestamp

# Get the scaling schedule for the current day of week
$dayObjects = $stateConfig | Where-Object {$_.WeekDays -contains $currentDayOfWeek } `
|Select-Object Edition, Tier, `
@{Name="StartTime"; Expression = {[datetime]::ParseExact(($startTime.ToString("yyyy:MM:dd")+”:”+$_.StartTime),"yyyy:MM:dd:HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture)}}, `
@{Name="StopTime"; Expression = {[datetime]::ParseExact(($startTime.ToString("yyyy:MM:dd")+”:”+$_.StopTime),"yyyy:MM:dd:HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture)}}

# Get the database object
$sqlDB = Get-AzureRmSqlDatabase `
-ResourceGroupName $resourceGroupName `
-ServerName $serverName `
-DatabaseName $databaseName
Write-Output "DB name: $($sqlDB.DatabaseName)" | timestamp
Write-Output "Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)" | timestamp

if($dayObjects -ne $null) { # Scaling schedule found for this day
    # Get the scaling schedule for the current time. If there is more than one available, pick the first
    $matchingObject = $dayObjects | Where-Object { ($startTime -ge $_.StartTime) -and ($startTime -lt $_.StopTime) } | Select-Object -First 1
    if($matchingObject -ne $null)
    {
        Write-Output "Scaling schedule found. Check if current edition/tier is matching..." | timestamp
        if($sqlDB.CurrentServiceObjectiveName -ne $matchingObject.Tier -or $sqlDB.Edition -ne $matchingObject.Edition)
        {
            Write-Output "DB is not in the edition and/or tier of the scaling schedule. Changing!" | timestamp
            $sqlDB | Set-AzureRmSqlDatabase -Edition $matchingObject.Edition -RequestedServiceObjectiveName $matchingObject.Tier | out-null
            Write-Output "Change to edition/tier as specified in scaling schedule initiated..." | timestamp
            $sqlDB = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName
            Write-Output "Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)" | timestamp
        }
        else
        {
            Write-Output "Current DB tier and edition matches the scaling schedule already. Exiting..." | timestamp
        }
    }
    else { # Scaling schedule not found for current time
        Write-Output "No matching scaling schedule time slot for this time found. Check if current edition/tier matches the default..." | timestamp
        if($sqlDB.CurrentServiceObjectiveName -ne $defaultTier -or $sqlDB.Edition -ne $defaultEdition)
        {
            Write-Output "DB is not in the default edition and/or tier. Changing!" | timestamp
            $sqlDB | Set-AzureRmSqlDatabase -Edition $defaultEdition -RequestedServiceObjectiveName $defaultTier | out-null
            Write-Output "Change to default edition/tier initiated." | timestamp
            $sqlDB = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName
            Write-Output "Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)" | timestamp
        }
        else
        {
            Write-Output "Current DB tier and edition matches the default already. Exiting..." | timestamp
        }
    }
}
else # Scaling schedule not found for this day
{
    Write-Output "No matching scaling schedule for this day found. Check if current edition/tier matches the default..." | timestamp
    if($sqlDB.CurrentServiceObjectiveName -ne $defaultTier -or $sqlDB.Edition -ne $defaultEdition)
    {
        Write-Output "DB is not in the default edition and/or tier. Changing!" | timestamp
        $sqlDB | Set-AzureRmSqlDatabase -Edition $defaultEdition -RequestedServiceObjectiveName $defaultTier | out-null
        Write-Output "Change to default edition/tier initiated." | timestamp
        $sqlDB = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName
        Write-Output "Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)" | timestamp
    }
    else
    {
        Write-Output "Current DB tier and edition matches the default already. Exiting..." | timestamp
    }
}

Write-Output "Script finished." | timestamp

Step-by-step setup guide

Navigate to the Azure portal and create an Azure Automation account in the same Azure Subscription as where the Azure SQL Database that you want to scale resides. Make sure the Run As account has been created. When you create a new Automation account in the Azure portal, it automatically creates a new service principal(Run As account) and assigns it the Contributor role-based access control (RBAC) role in the subscription by default. These rights are sufficient to scale Azure SQL Databases.

I have uploaded my PowerShell script to TechNet Script Center so you can easily import it as Runbook. Navigate to your Automation Account and click the “Runbooks Gallery” menu item. Make sure you filter the Gallery Source on “Script Center” and search for “Azure SQL Database – Scale using scheduled autoscaling”. Open the item from the gallery and click Import.
Runbooks Gallery

Before you can use the runbook you have to publish it first. Click on “Overview” if you are not already on that page and then click “Edit”.
Edit Runbook

Now click “Publish”.
Publish Runbook

The runbook is now ready to use. Next step is to schedule it to run hourly, of course with your desired parameters. Click “Schedules” and then “Add a schedule”.
Schedule Runbook

Give your schedule a name, set the start time on a whole hour, the Recurrence on “Recurring”, Recur every “1 Hour” and Set expiration to “No”.
Recurring Schedule Runbook

Now configure the parameters. Explanation can be found under “The Runbook PowerShell script” earlier in this article.
Schedule Runbook Parameters

When you now navigate to “Jobs” you get an overview of all executions.
Runbook Jobs

When you open a job and look at the Output, you will see all details of that particular run. For example, I can see my database was scaled up from S0 to S1 on Friday at 07:00.
Job Output

84 comments

  1. Jorge,

    Great post, but I found out that the Price Tier Premium RS is not working. You should use the Edition NONE. Very strange, but true. Maybe it has something todo with the Public Preview
    See below the output of the script
    Current DB status: Online, edition: None, tier: PRS1

    Liked by 1 person

    1. Hi Erwin (and Jorg),

      For Premium RS edition you can use the parameter value “PremiumRS”.
      Tiers can have values “PRS1” until “PRS6”.

      Cheers,
      Dave

      Liked by 1 person

      1. Thanks Dave! If you still run into the error you need to update your Azure Automation Modules (AzureRM.Sql). I have added this to the step-by-step instructions.

        Like

      2. Cannot bind parameter ‘Edition’. Cannot convert value “PremiumRS” to type “Microsoft.Azure.Commands.Sql.Database.Model.DatabaseEdition”. Error: “Unable to match the identifier name PremiumRS to a valid enumerator name. Specify one of the following enumerator names and try again: None, Premium, Basic, Standard, DataWarehouse, Free” (Cannot bind parameter ‘Edition’. Cannot convert value “PremiumRS” to type “Microsoft.Azure.Commands.Sql.Database.Model.DatabaseEdition”. Error: “Unable to match the identifier name PremiumRS to a valid enumerator name.

        Like

    2. I dint get that how shall I enter the higher Vcores in this code?
      For eg. Case1: Vcores=2, Size=500 GB; Case 2: Vcores=8, Size=500 GB
      If I want to autoscale(from Case1 to Case2) how to put that in your code?

      Like

  2. Hi Dave. I thinlk that the hourly scheduling is not accurate. Maybe yo can schudule Once and while waiting for time to scaling.

    while($true) {
    ######## YOUR PROCESS
    $d = Get-Date
    Write-Output $d
    Start-Sleep -Milliseconds 60000
    }

    Like

    1. Hi Esteban, it can take a minute before the script actually starts when the runbook is scheduled, so it’s not accurate on the second. But keep in mind it can (in theory) take hours before a scaling operation finishes, so why worry about the runbook schedule accuracy? Or do you mean something else?

      Liked by 1 person

      1. I use a webhook to fire script every 3 minutes. And my database needs more than one hour to swich plan. But I modoify your script putting a global flag (variable asset).
        thanks anyway

        Liked by 1 person

      1. Hi Dong Ning,
        It might have something to do with the scalingSchedule parameter as this is in JSON. Can you copy paste the value you provided so I can take a look?

        Make sure it follows the following formatting (no line feeds):
        [{WeekDays:[1], StartTime:”06:59:59″, StopTime:”17:59:59″, Edition: “Premium”, Tier: “P2″}, {WeekDays:[2,3,4,5], StartTime:”06:59:59″, StopTime:”17:59:59”, Edition: “Premium”, Tier: “P1”}]

        Like

          1. Did you import the script from the Runbooks Gallery? Maybe something went wrong with copy/pasting from this blog?
            There are many people that have this script running as Runbook without any problems, so it must work!

            Like

        1. I copied the JSON *precisely* as in your example, but still receive the, “Invalid JSON primitive: . (Invalid JSON primitive: .)” exception. No errors and no warnings.

          Like

  3. Yes, I import scripts from Runbooks Gallery.

    The Runbook is now functioning but cannot upgrade the specifications.

    Output log:
    [10/25/2017 6: The following: I AM]: Script started.

    [10/25/2017 6:: i]: authenticated with the Automation Run as account.

    [10/25/2017 6:: i]: Azure Automation local time: 10/25/2017 06:20:45.

    [10/25/2017 6: AM: i]: time zone to convert to: (utc+08: $number) Taipei.

    [10/25/2017 6: I AM]: converted time: 10/25/2017 14:20:45.

    [10/25/2017 6: I AM]: Current day of week: 3.

    [10/25/2017 6: I AM]: DB Name: greedyu01

    [10/25/2017 6: I AM]: current DB Status: Online, Edition: Standard, Tier: S1

    [10/25/2017 6: I AM]: No matching scaling schedule time slot for this time found. Check if current edition/tier matches the default …

    [10/25/2017 6: I AM]: current DB tier and edition matches the default already. Exiting …

    [10/25/2017 6: I AM]: Script finished.

    This is my scalingschedule:
    [{WeekDays:[1,2,3,4,5],StartTime:”14:35:00″,StopTime:”17:59:59″, Edition:”Standard”, Tier:”S3″}]

    I want to set the spec in 30 minutes, but all failed.

    Like

    1. It’s not possible to create a schedule with a recurrence of 30 minutes, so create an hourly one that you start on a whole hour (in my example it starts at 4:00:00 PM). Then use the following scalingSchedule to scale starting at 15:00, and again at 18:00:

      [{WeekDays:[1,2,3,4,5],StartTime:”14:59:59″,StopTime:”17:59:59″, Edition:”Standard”, Tier:”S3″}]

      Like

      1. I’m testing the script to set tomorrow morning at 6 o ‘ clock.

        [{WeekDays:[1,2,3,4,5],StartTime:”06:59:59″,StopTime:”17:59:59″, Edition:”Standard”, Tier:”S3″}]

        Error message:
        [10/25/2017 8:50:35 AM]: No matching scaling schedule time slot for this time found. Check if current edition/tier matches the default…
        [10/25/2017 8:50:35 AM]: DB is not in the default edition and/or tier. Changing!

        Like

        1. If you want it to scale to S3 at 06:00 you should use:
          [{WeekDays:[1,2,3,4,5],StartTime:”05:59:59″,StopTime:”17:59:59″, Edition:”Standard”, Tier:”S3″}]

          Like

  4. I am also getting an “Invalid JSON primitive” error. This is for the “scalingSchedule” parameter. I have used “TestSchedule1”, “TestSchedule” and “Schedule3”, all with the same result. On my final attempt, I was sure to set the schedule on a whole hour.

    Like

    1. Hi Jacob, the mistake most people make is that the schedule contains a CRLF (enter). Try copy/pasting your scalingSchedule to Notepad and make sure it’s on 1 line before using it.

      Like

      1. Initially, I misunderstood the scalingSchedule field and was entering it as the name of the schedule. I looked at the example and tried to edit my entry accordingly. I attempted several iterations and kept getting invalid JSON errors. One such example:
        [{WeekDays:[2], StartTime:”00:00:00″, StopTime:”23:59:59”, Edition: “Standard”, Tier: “S0”}]
        I kept trying, adding or removing quotes, removing spaces. But nothing worked. Finally I just tried to simplify it and only specify the tier:
        [{Tier: “S0”}]
        This worked. I’m not sure what is wrong with the more detailed attempts.

        Liked by 2 people

        1. Hi Jacob,
          I think you should look at the quotation marks “”. Sometimes it’s difficult to see what’s wrong, but once it’s in good format you will be good to go, so don’t give up yet 😉
          Let me know if I can help.
          Jorg

          Like

          1. Hi Jorg,
            How can you schedule it if you want to have the Paas to scale down to Standard/S0 Durant off hours and take no action business hours. That is if the users modifier the edition/tier during business hours I don’t want to change it.

            Thanks for your insight

            Like

          2. Hi Barry,

            You should be able to do this, but it will need some changes in the Workbook code.
            If you completely remove or comment the last ‘else’ part in the code, you should be fine (it starts at this line):
            “else # Scaling schedule not found for this day”

            Then you specify the ‘off-hours’ in the schedule, with the S0 tier.

            Let me know if it works or if you need more help.

            Cheers,
            Dave

            Liked by 1 person

  5. Hi Dave,

    thanks for your reply. I have tried that before but noting is happening and the issue I am having is that let say from 16:59:59 to 07:59:59 –> Standard/S0.
    Somewhere this condition is not matching “$matchingObject = $dayObjects | Where-Object { ($startTime -ge $_.StartTime) -and ($startTime -lt $_.StopTime) } | Select-Object -First 1”
    because of the midnight time 00:00:00. at that point the start time is not greater or equal to schedule start time.

    I think we need to check if time =00:00 then considere it as the next day.

    Your thoughts on this?

    Once again thanks.

    Barry

    Like

  6. Hi Jorg,

    I run scaling schedule : [{“WeekDays”:[1,2,3,4,5],”StartTime”:”04:59:59″,”StopTime”:”17:59:59″,”Edition”:”Standard”,”Tier”:”S2″}]
    which should make my database S2 from default S1 ( I changed it from S0 to S1).
    Also i am running in : AUS Eastern Standard Time as scaling time zone. Issue is the scaling up is happening at 10 AM rather than 5 AM.
    [6/27/2018 7:00:38 PM]: Script started.
    [6/27/2018 7:00:49 PM]: Authenticated with Automation Run As Account.
    [6/27/2018 7:00:49 PM]: Azure Automation local time: 06/27/2018 19:00:49.
    [6/27/2018 7:00:49 PM]: Time zone to convert to: (UTC+10:00) Canberra, Melbourne, Sydney.
    [6/27/2018 7:00:49 PM]: Converted time: 06/28/2018 05:00:49
    [6/27/2018 7:00:49 PM]: Current day of week: 4.
    [6/27/2018 7:00:51 PM]: DB name: objtestapg23dfgs35ds
    [6/27/2018 7:00:51 PM]: Current DB status: Online, edition: Standard, tier: S1
    [6/27/2018 7:00:51 PM]: No matching scaling schedule time slot for this time found. Check if current edition/tier matches the default…
    [6/27/2018 7:00:51 PM]: Current DB tier and edition matches the default already. Exiting…

    AT 10 AM it scales up i am not sure where script is picking this up from ? :
    [6/28/2018 12:00:44 AM]: Script started.
    [6/28/2018 12:00:55 AM]: Authenticated with Automation Run As Account.
    [6/28/2018 12:00:55 AM]: Azure Automation local time: 06/28/2018 00:00:55.
    [6/28/2018 12:00:55 AM]: Time zone to convert to: (UTC+10:00) Canberra, Melbourne, Sydney.
    [6/28/2018 12:00:55 AM]: Converted time: 06/28/2018 10:00:55.
    [6/28/2018 12:00:55 AM]: Current day of week: 4.
    [6/28/2018 12:00:57 AM]: DB name: objtestapg23dfgs35ds
    [6/28/2018 12:00:58 AM]: Current DB status: Online, edition: Standard, tier: S1
    [6/28/2018 12:00:58 AM]: Scaling schedule found. Check if current edition & tier is matching…
    [6/28/2018 12:00:58 AM]: DB is not in the edition and/or tier of the scaling schedule. Changing!
    [6/28/2018 12:04:32 AM]: Change to edition/tier as specified in scaling schedule initiated…
    [6/28/2018 12:04:33 AM]: Current DB status: Online, edition: Standard, tier: S2
    [6/28/2018 12:04:33 AM]: Script finished.
    [6/27/2018 7:00:51 PM]: Script finished.

    However scaling down occurs correctly as per schedule at 6 PM:
    [6/28/2018 8:00:38 AM]: Script started.
    [6/28/2018 8:00:48 AM]: Authenticated with Automation Run As Account.
    [6/28/2018 8:00:48 AM]: Azure Automation local time: 06/28/2018 08:00:48.
    [6/28/2018 8:00:48 AM]: Time zone to convert to: (UTC+10:00) Canberra, Melbourne, Sydney.
    [6/28/2018 8:00:48 AM]: Converted time: 06/28/2018 18:00:48.
    [6/28/2018 8:00:48 AM]: Current day of week: 4.
    [6/28/2018 8:00:50 AM]: DB name: objtestapg23dfgs35ds
    [6/28/2018 8:00:51 AM]: Current DB status: Online, edition: Standard, tier: S2
    [6/28/2018 8:00:51 AM]: No matching scaling schedule time slot for this time found. Check if current edition/tier matches the default…
    [6/28/2018 8:00:51 AM]: DB is not in the default edition and/or tier. Changing!
    [6/28/2018 8:03:55 AM]: Change to default edition/tier initiated.
    [6/28/2018 8:03:56 AM]: Current DB status: Online, edition: Standard, tier: S1
    [6/28/2018 8:03:56 AM]: Script finished.

    Please guide on how get scale at scheduled time?

    Thanks,
    Rupesh

    Like

  7. Hi Jorg,
    getting an error on line 87
    At line:87 char:73 + … calingSchedule = “scalingSchedule [{WeekDays:[1], StartTime:”06:59:59 … + ~ Missing ‘)’ in function parameter list. At line:87 char:241 + … :”06:59:59″, StopTime:”19:59:59”, Edition: “Standard”, Tier: “S3″}]”, + ~ Missing argument in parameter list.
    though the line looks fine;
    [string] $scalingSchedule = “scalingSchedule [{WeekDays:[1], StartTime:”05:59:59″, StopTime:”19:59:59”, Edition: “Standard”, Tier: “S4″}, {WeekDays:[2,3,4,5,6,0], StartTime:”05:59:59″, StopTime:”19:59:59”, Edition: “Standard”, Tier: “S3″}]”,
    Any suggestions

    Like

      1. That is something which goes wrong often while copy/pasting unfortunately. I don’t know how to make the text copy/paste proof, so make sure to double check 🙂

        Like

  8. Hello Jorg,

    Seems like your script doesn’t detect a schedule on weekend and also on any day after 5PM, e.g. if i want to keep a db at S7 from 5AM to 10PM, i’ll provide the following schedule

    [{WeekDays:[1,2,3,4,5],StartTime:”04:59:59″,StopTime:”21:59:59″, Edition:”Standard”, Tier:”S7″}]

    what happens is after 5PM it says, “no schedule was found” and db is scaled to the default edition and tier.
    I want to be able to specify a schedule for any hour, how is that possible?

    Thanks in advance

    Like

  9. Thank you for your post. I was able to use a modified version of your script to scale up and down Azure PAAS instances. I ran into one issue and wanted to make you aware. It would not work for me until I added this in:

    $Environment = Get-AzureRmEnvironment -Name “NameOfMyEnvironment”
    Add-AzureRmAccount -Environment $Environment …

    I needed to grab the correct environment first, and then specify that environment for the Add-AzureRmAccount command. Otherwise, the command would grab the first available environment which was not what our subscription is associated with. The default one it selected was the commercial cloud. We are a government agency, so this affected us, but probably not anyone using the commercial cloud.

    Liked by 1 person

  10. I am trying to include a sendmail option within this script to notify the scaling status. However I am unable to succeed with this. Please chime in your feedback. I am using the below piece of code

    Send-MailMessage `
    -To $To `
    -Cc $Cc `
    -Subject $Subject `
    -Body $Body `
    -Port 587 `
    -SmtpServer ‘smtp.office365.com’ `
    -From $From `
    -BodyAsHtml `
    -Credential $Cred

    Write-Output “Mail is now send `n”
    Write-Output “————————————————————————-“

    Like

  11. For the ones with timing (time zone) issues, Seth C. was so kind to share a fix for it on the Azure Analysis Services version of this script: https://jorgklein.com/2017/10/11/azure-analysis-services-scheduled-autoscaling/comment-page-1/#comment-938

    This is a bit belated but I had the same issue as Nick McDermaid and Ruby M. I believe the issue is that the Azure Automation account interprets these lines in UTC time:

    @{Name=”StartTime”; Expression = {[datetime]::ParseExact($_.StartTime,”HH:mm:ss”, [System.Globalization.CultureInfo]::InvariantCulture)}}, `
    @{Name=”StopTime”; Expression = {[datetime]::ParseExact($_.StopTime,”HH:mm:ss”, [System.Globalization.CultureInfo]::InvariantCulture)}}

    This can cause time zone issues at the day rollover for scheduling (in my case I tried to spin down AAS at midnight and it was shutting down at 7pm EST.) I fixed the issue by getting the day from the $startTime variable and combining it with the start/stop schedule time. I updated the code to use the following:

    @{Name=”StartTime”; Expression = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StartTime),”yyyy:MM:dd:HH:mm:ss”, [System.Globalization.CultureInfo]::InvariantCulture)}}, `
    @{Name=”StopTime”; Expression = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StopTime),”yyyy:MM:dd:HH:mm:ss”, [System.Globalization.CultureInfo]::InvariantCulture)}}

    Liked by 1 person

  12. Hi Jorg,
    This is my first foray into Azure Automation and I am trying to use your PowerShell script. I am not having much success getting the Runbook to execute. I get the following error:

    Failed
    Parameter set cannot be resolved using the specified named parameters. (Parameter set cannot be resolved using the specified named parameters.)

    Any suggestions on what it could it be? If not, is there a way to run the powershell in debug mode?

    Here is my copy of your script with the parameters set for our application:

    ————————————————————————————————-
    param(
    [parameter(Mandatory=$false)]
    [string] $environmentName = “AzureCloud”,

    [parameter(Mandatory=$true)]
    [string] $resourceGroupName = “DevOps”,

    [parameter(Mandatory=$false)]
    [string] $azureRunAsConnectionName = “AzureRunAsConnection”,

    [parameter(Mandatory=$true)]
    [string] $serverName = “azuresql-litens-qa.database.windows.net”,

    [parameter(Mandatory=$true)]
    [string] $databaseName = “QSYS”,

    [parameter(Mandatory=$true)]
    [string] $scalingSchedule = “[{WeekDays:[0,1,2,3,4,5,6], StartTime:″10:30:00″, StopTime:″13:00:00″, Edition: ″Standard″, Tier: ″S3″}]”,

    [parameter(Mandatory=$false)]
    [string] $scalingScheduleTimeZone = “GMT Standard Time”,

    [parameter(Mandatory=$false)]
    [string] $defaultEdition = “Standard”,

    [parameter(Mandatory=$false)]
    [string] $defaultTier = “S1”
    )

    filter timestamp {“[$(Get-Date -Format G)]: $_”}

    Write-Output “Script started.” | timestamp

    $VerbosePreference = “Continue”
    $ErrorActionPreference = “Stop”

    #Authenticate with Azure Automation Run As account (service principal)
    $runAsConnectionProfile = Get-AutomationConnection -Name $azureRunAsConnectionName
    $environment = Get-AzureRmEnvironment -Name $environmentName
    Add-AzureRmAccount -Environment $environment -ServicePrincipal `
    -TenantId $runAsConnectionProfile.TenantId `
    -ApplicationId $runAsConnectionProfile.ApplicationId `
    -CertificateThumbprint ` $runAsConnectionProfile.CertificateThumbprint | Out-Null
    Write-Output “Authenticated with Automation Run As Account.” | timestamp

    #Get current date/time and convert to $scalingScheduleTimeZone
    $stateConfig = $scalingSchedule | ConvertFrom-Json
    $startTime = Get-Date
    Write-Output “Azure Automation local time: $startTime.” | timestamp
    $toTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById($scalingScheduleTimeZone)
    Write-Output “Time zone to convert to: $toTimeZone.” | timestamp
    $newTime = [System.TimeZoneInfo]::ConvertTime($startTime, $toTimeZone)
    Write-Output “Converted time: $newTime.” | timestamp
    $startTime = $newTime

    #Get current day of week, based on converted start time
    $currentDayOfWeek = [Int]($startTime).DayOfWeek
    Write-Output “Current day of week: $currentDayOfWeek.” | timestamp

    # Get the scaling schedule for the current day of week
    $dayObjects = $stateConfig | Where-Object {$_.WeekDays -contains $currentDayOfWeek } | Select-Object Edition, Tier, `
    @{Name=”StartTime”; Expression = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StartTime),”yyyy:MM:dd:HH:mm:ss”, [System.Globalization.CultureInfo]::InvariantCulture)}}, `
    @{Name=”StopTime”; Expression = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StopTime),”yyyy:MM:dd:HH:mm:ss”, [System.Globalization.CultureInfo]::InvariantCulture)}}

    # Get the database object
    $sqlDB = Get-AzureRmSqlDatabase `
    -ResourceGroupName $resourceGroupName `
    -ServerName $serverName `
    -DatabaseName $databaseName
    Write-Output “DB name: $($sqlDB.DatabaseName)” | timestamp
    Write-Output “Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)” | timestamp

    if($dayObjects -ne $null) { # Scaling schedule found for this day
    # Get the scaling schedule for the current time. If there is more than one available, pick the first
    $matchingObject = $dayObjects | Where-Object { ($startTime -ge $_.StartTime) -and ($startTime -lt $_.StopTime) } | Select-Object -First 1
    if($matchingObject -ne $null)
    {
    Write-Output “Scaling schedule found. Check if current edition/tier is matching…” | timestamp
    if($sqlDB.CurrentServiceObjectiveName -ne $matchingObject.Tier -or $sqlDB.Edition -ne $matchingObject.Edition)
    {
    Write-Output “DB is not in the edition and/or tier of the scaling schedule. Changing!” | timestamp
    $sqlDB | Set-AzureRmSqlDatabase -Edition $matchingObject.Edition -RequestedServiceObjectiveName $matchingObject.Tier | out-null
    Write-Output “Change to edition/tier as specified in scaling schedule initiated…” | timestamp
    $sqlDB = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName
    Write-Output “Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)” | timestamp
    }
    else
    {
    Write-Output “Current DB tier and edition matches the scaling schedule already. Exiting…” | timestamp
    }
    }
    else { # Scaling schedule not found for current time
    Write-Output “No matching scaling schedule time slot for this time found. Check if current edition/tier matches the default…” | timestamp
    if($sqlDB.CurrentServiceObjectiveName -ne $defaultTier -or $sqlDB.Edition -ne $defaultEdition)
    {
    Write-Output “DB is not in the default edition and/or tier. Changing!” | timestamp
    $sqlDB | Set-AzureRmSqlDatabase -Edition $defaultEdition -RequestedServiceObjectiveName $defaultTier | out-null
    Write-Output “Change to default edition/tier initiated.” | timestamp
    $sqlDB = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName
    Write-Output “Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)” | timestamp
    }
    else
    {
    Write-Output “Current DB tier and edition matches the default already. Exiting…” | timestamp
    }
    }
    }
    else # Scaling schedule not found for this day
    {
    Write-Output “No matching scaling schedule for this day found. Check if current edition/tier matches the default…” | timestamp
    if($sqlDB.CurrentServiceObjectiveName -ne $defaultTier -or $sqlDB.Edition -ne $defaultEdition)
    {
    Write-Output “DB is not in the default edition and/or tier. Changing!” | timestamp
    $sqlDB | Set-AzureRmSqlDatabase -Edition $defaultEdition -RequestedServiceObjectiveName $defaultTier | out-null
    Write-Output “Change to default edition/tier initiated.” | timestamp
    $sqlDB = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverName -DatabaseName $databaseName
    Write-Output “Current DB status: $($sqlDB.Status), edition: $($sqlDB.Edition), tier: $($sqlDB.CurrentServiceObjectiveName)” | timestamp
    }
    else
    {
    Write-Output “Current DB tier and edition matches the default already. Exiting…” | timestamp
    }
    }

    Write-Output “Script finished.” | timestamp

    Like

  13. Thanks for the great script, and clear instructions on how to set it up. Got everything working in one try.
    One thing I did notice: I have one or more tags set up on the databases. After a tier change using this script, the tags are gone. Is that correct, and if so, is there a possibility to let it keep the tags?

    Like

  14. Thanks for the great script, I’ve just got it working. As a note though, I pulled it from gallery and it had the below issue that the +”:”+ element in the script has got corupted and appears as +”:”+, on the StatTime and StopTime tags.
    “@{Name=”StartTime”; Expression = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StartTime),”yyyy:MM:dd:HH:mm:ss”, [System.Globalization.CultureInfo]::InvariantCulture)}}, `”

    Also as a note for anyone else the server name excludes the “.database.windows.net” part at the end.

    Liked by 1 person

  15. Hi guys I am getting the following exception.

    Exception
    At line:138 char:93
    + … = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+ …
    + ~ You must provide a value expression following the ‘+’ operator.

    At line:138 char:93
    + … Exact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StartTime),”yyyy: …
    + ~~~~~~~~~~~~~~~~~~~~ Unexpected token ‘”:”+$_.StartTime’ in expression or statement.

    At line:138 char:93
    + … = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+ …
    + ~ Missing closing ‘)’ in expression.

    At line:138 char:93
    + … = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+ …
    + ~ Missing ‘)’ in method call.

    At line:138 char:34
    + @{Name=”StartTime”; Expression = {[datetime]::ParseExact(($startTime. …
    + ~ Missing closing ‘}’ in statement block or type definition.

    At line:138 char:113
    + … Exact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StartTime),”yyyy: …
    + ~ The hash literal was incomplete.

    At line:138 char:113
    + … xact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StartTime),”yyyy:M …
    + ~ Unexpected token ‘)’ in expression

    Like

    1. Thank you Anthony David Cook I missed your post and went back and corrected the +”:”+ so that the element is +”:”+ and this fixed my issue.

      Liked by 1 person

  16. Hey,

    Trying to do the script but having issue with Json “Invalid JSON primitive: . (Invalid JSON primitive: .)”

    Name

    Input value
    ENVIRONMENTNAME

    “AzureCloud”
    DATABASENAME

    “xxxxx”
    SERVERNAME

    “xx1”
    RESOURCEGROUPNAME

    “xxxx”
    AZURERUNASCONNECTIONNAME

    “AzureRunAsConnection”
    DEFAULTEDITION

    “Standard”
    DEFAULTTIER

    “S0”
    SCALINGSCHEDULE

    “[{WeekDays:[1],StartTime:”22:15:59″,StopTime:”23:59:59″, Edition:”Standard”, Tier:”S4″}]”
    SCALINGSCHEDULETIMEZONE

    “W. Europe Standard Time”

    Like

  17. Hello Jorg,

    Nice article, I’m going to give it a try soon! A few questions:
    1) You wrote that a switch should be generally under 4 seconds, and under 30 seconds 99% of the time, but that the duration of the entire scale process could be as long as 6 HOURS on the Standard tier. I was a little confused by the variations – could you elaborate a little, or point me where in the Azure doc I could learn more about that, if you know where? I’m sure we could not tolerate a “downtime” of 6 hours, but perhaps you mean the initial prep of the replica, not the actual switch to replica time?
    2) We would obviously only make a scale change during an expected low-traffic time, but if any transactions would be rolled back, then it would be up to our application or supporting layers to re-submit that transaction to avoid any dataloss, correct? But the switch time is expected to be relatively short, correct, like the 4-30 seconds you listed above, right?

    Thanks in advance for any feedback!
    Bo.

    Like

  18. Extremely useful piece of script. I have found 3 challenges and thought to mention it here for help to other viewers like me:

    1. Azure Run As account: Please make sure that the account you are using to create the ‘Automation’ does have permission to create ‘Azure Run As Account’, i.e. permission to create service principal in your Azure AD is required.

    2. Do not use fully qualified name for the database server while adding parameters for the schedule. i.e. remove “.database.windows.net” part from your SQL Server name, else you will see ‘Resource was not found’ error, indicating that the resource ‘Microsoft.Sql/servers/YOURSQLSERVERNAME.database.windows.net/databases/YOURDBNAME’ under resource group ‘YOUR_ResourceGroup’ was not found.

    3. You need to modify the script to remove the ‘+”:”’ characters from the script and replace them with “:” value.

    Error:
    At line:138 char:93
    + … = {[datetime]::ParseExact(($startTime.ToString(“yyyy:MM:dd”)+”:”+ …
    + ~ You must provide a value expression following the ‘+’ operator.

    At line:138 char:93
    + … Exact(($startTime.ToString(“yyyy:MM:dd”)+”:”+$_.StartTime),”yyyy: …

    Like

    1. Hi Ukb,

      It is actually erroring out because the at line 138, you see the start date and stop date parameters.

      Please edit your runbook and replace ”:” with “:”(including the double quotes). this is what you should replace it with “:”

      After replacing it, please republish it and it should work file.

      -Surya

      Like

  19. when i try to scale down the database from P4 to P1 i keep getting this error message –

    The running command stopped because the preference variable “ErrorActionPreference” or common parameter is set to Stop: Long running operation failed with status ‘Failed’. Additional Info:’MODIFY MAXSIZE failed. The requested database size is smaller than the amount of data storage used.’

    Can anyone please suggest a fix/workaround ?

    Thanks

    Like

    1. Hi Don,
      Exactly even I wanted to set vcore based parameters but not able to find out yet..Everywhere it is mentioned in terms of DTUs.
      Did you figure out anything on this or anybody here ? If yes please let me know. TIA.

      Jiya

      Like

  20. Hello Im trying to run the script but I receive this error:

    At line:62 char:1 + |Select-Object Edition, Tier, ` + ~ An empty pipe element is not allowed.

    Like

  21. Your last version to be used on Azure is not working, due to nonprintable characters in the ParseExact on the date and time.

    Like

  22. Hi Jorg Klein ,

    I want to scale SQL database Edition’s DTUs. Your post doesn’t mention any method to change DTUs for a specific Edition. For example what if I want to change DTUs to 40/100/150 for Edition “S1” using your script? Is this possible?

    Like

  23. I am facing an issue while running the job

    The running command stopped because the preference variable “ErrorActionPreference” or common parameter is set to Stop: ResourceNotFound: The Resource ‘Microsoft.Sql/servers/devenvironment.database.windows.net/databases/MyDB’ under resource group ‘MyResourceGroup’ was not found.

    can you please help me out?

    Like

    1. Hi Vipin, Please check below two thing:
      1. on the DB server Name field, remove .database.windows.net part if you have included it.
      2. Check DB is in the same resource group and Azure Automation account has access to the resource group

      Like

  24. It’s very useful and able to scale down and up the SQL DB. had to edit the script since there was unknown letters came in after the + sign in start and End time variables.

    Like

  25. Thanks for the runbook. I have just imported it again and the version in the marketplace also has the problem with the quotes +”:”+. Could you please fix that ?

    Like

  26. AM trying to get your script to work and am running into a strange problem – it looks suspiciously like a formatting issue, as the character a test shows as missing in the function parameter list is actually in the list at line 103

    I’ve tried various forms of parentheses, but to no avail – I must be missing something obvoius, but I cannot for the life of me see what

    Care to take a look? Here’s my scalingSchedule
    ¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
    [string] $scalingSchedule = “[{WeekDays:[0,1,2,3,4,5,6],StartTime:”23:45:00”,StopTime:”00:15:00”,Edition:”Standard”,Tier:”S5”}]”,

    And here is the error I get when I test the script
    ¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
    Failed
    At line:93 char:68
    + … g] $scalingSchedule = “[{WeekDays:[0,1,2,3,4,5,6],StartTime:”23:45:00 …
    + ~
    Missing ‘)’ in function parameter list.

    At line:93 char:129
    + … tTime:”23:45:00”,StopTime:”00:15:00”,Edition:”Standard”,Tier:”S5”}]”,
    + ~
    Missing argument in parameter list.

    At line:103 char:1
    + )
    + ~
    Unexpected token ‘)’ in expression or statement.

    At line:96 char:37
    + [string] $scalingScheduleTimeZone = “GMT Standard Time”,
    + ~~~~~~~~~~~~~~~~~~~
    The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept assignments, such as a variable or a property.

    At line:99 char:28
    + [string] $defaultEdition = “Standard”,
    + ~~~~~~~~~~
    The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept assignments, such as a variable or a property.

    Like

  27. Hi,
    My script somehow it didn’t work

    This is the setting:

    ‘[{WeekDays:[1,2,3,4,5], StartTime:”08:59:59″, StopTime:”14:59:59″, Edition:”Standard”, Tier:”S1″}]’
    SE Asia Standard Time
    Standard
    S0

    The command runs, but it didn’t change the tier.
    [6/17/2020 2:00:39 AM]: Authenticated with Automation Run As Account.
    [6/17/2020 2:00:39 AM]: Azure Automation local time: 06/17/2020 02:00:39.
    [6/17/2020 2:00:39 AM]: Time zone to convert to: (UTC+07:00) Bangkok, Hanoi, Jakarta.
    [6/17/2020 2:00:39 AM]: Converted time: 06/17/2020 09:00:39.
    [6/17/2020 2:00:39 AM]: Current day of week: 3.
    [6/17/2020 2:00:40 AM]: DB name: sql-single-db
    [6/17/2020 2:00:40 AM]: Current DB status: Online, edition: Standard, tier: S0
    [6/17/2020 2:00:40 AM]: No matching scaling schedule for this day found. Check if current edition/tier matches the default…
    [6/17/2020 2:00:40 AM]: Current DB tier and edition matches the default already. Exiting…
    [6/17/2020 2:00:41 AM]: Script finished.

    Let me know if I did something wrong.

    Like

  28. The running command stopped because the preference variable “ErrorActionPreference” or common parameter is set to Stop: Connections asset not found. To create this Connections asset, navigate to the Assets blade and create a Connections asset named: AzureRunAsConnection.

    Like

  29. “PowerShell script to TechNet Script Center ” link above doesnt work. Could you point to how to change scaling for elastic pool

    Like

  30. Can we run this script for multiple SQL databases under same resource group? Currently , we can scale down and scale up single Database by using this script. Any modified version of this available

    Like

  31. Thanks heaps for the script and writeup Jorg.

    I had some issues with the “No matching scaling schedule for this day found. Check if current edition/tier matches the default” as well and managed to get it going with the following:
    1) Opened the scalingschedule JSON e.g. [{WeekDays:[1], StartTime:”06:59:59″, StopTime:”17:59:59″, Edition: “Premium”, Tier: “P2″}, {WeekDays:[2,3,4,5], StartTime:”06:59:59″, StopTime:”17:59:59”, Edition: “Premium”, Tier: “P1”}] in VSCode and found the double quotes in it were.
    The property keys (WeekDays, StartTime etc) just needed double quotes around them. Plus replace the existing double quotes in VSCode if you have cut and pasted it. For some reason, double quotes when you cut from a website or a word do are different and the JSON doesn’t like it.
    This worked for me:
    [{“WeekDays”:[0,1,2,3,4,5,6], “StartTime”:”10:30:00″,”StopTime”:”13:00:00″, “Edition”: “Standard”, “Tier”: “S3”}]
    2) The other issue i found was that the $dayobjects variable worked if I removed the parsing of the StartTime and StopTime. So I updated to the following:
    $dayObjects = $stateConfig | Where-Object {$_.WeekDays -contains $currentDayOfWeek } `
    | Select-Object Edition, Tier, StartTime, StopTime

    After that, it started to run without errors and finding the matching schedule for the day
    One caveat ill say here is that I have edited it in my runbook to use the Az module. But I hope this helps someone

    Like

  32. Very Nice! However we want to run this under the new functionality of User Assigned Managed Identities. How would this script change to handle User Assigned Managed Identities instead?

    Like

    1. I used system assigned managed and here are the steps for that:
      1. Tick the identity box on the automation account
      2. Install the Az.Accounts and Az.SQL modules in the automation account.
      3. Add “Connect-AzAccount -Identity” to the runbook somewhere above the Get and Set SQL commands.
      4. Update the Get-AzureRmSqlDatabase and Set-AzureRmSqlDatabase to Get-AzSqlDatabase and Set-AzSqlDatabase
      5. Go to the azure SQL server and assign SQL DB Contributor to the identity/enterprise app created by step 1.

      Like

  33. I’m using the $scalingSchedule = {WeekDays:[1,2,3,4,5], StartTime:”14:59:59″, StopTime:”21:59:59″, Edition: “Premium”, Tier: “P6”}

    I am getting the error: “~ Missing argument in parameter list.”

    Any help?

    Like

Leave a comment