You dont have javascript enabled! Please enable it!

Schedule Start/Stop for Azure VM with Azure Function

10 Min. Read

Cost management is one of the things to watch out for when managing Azure resources. If you look at the Azure usage report, Azure virtual machine usage would probably be the highest cost contributor to your bill.

As a cost management best practice is to assess whether your virtual machines need to be up and running always or if some can be stopped at a specific schedule to save operational costs. In this case, it may be beneficial to create a schedule to stop and start your Azure virtual machines.

In this article, you will learn how to create an Azure Function where you can automate and schedule the start and stop of your Azure virtual machines using Tags and save costs.

Introduction

Auto-Shutdown Azure VMs by schedule is already a built-in feature in the platform which you can find under the Operations section as shown in the figure below, however, Azure does not have an AutoStart option.

Azure VM Auto-Shutdown
Azure VM Auto-Shutdown

The good news is, that Azure provides multiple options to automate and schedule the startup of your virtual machines, and each option has its pros and cons. I will list the different options below so you can decide which option makes sense for you, is scalable, easy to manage, and is cheaper.

Azure Automation

Azure Automation delivers a cloud-based automation and configuration service that supports consistent management across your Azure and non-Azure environments. It comprises process automation, configuration management, update management, shared capabilities, and heterogeneous features. Automation gives you complete control during deployment, operations, and decommissioning of workloads and resources. To automate the schedule of your virtual machines, you create first an automation account and then follow the steps described in this article.

Automation Tasks (preview)

Microsoft recently announced that you can manage your Azure resources more easily, where you can create automated management tasks for a specific resource or resource group by using automation task templates, which vary in availability based on the resource type. For example, for an Azure storage account, you can set up an automation task that sends you the monthly cost for that storage account. For an Azure virtual machine, you can create an automation task that turns on or turns off that virtual machine on a predefined schedule,  you can follow the steps shown in this video by my dear friend Thomas Maurer.

At the time of this writing, the automation tasks option is in preview, it’s not recommended for production workloads, and is excluded from service level agreements.

Azure Functions (the topic of this article)

With Azure Functions, you can develop more efficiently, an event-driven serverless compute platform that can also solve complex orchestration problems. You can build and debug locally without additional setup, deploy and operate at scale in the cloud, and integrate services using triggers and bindings.

You can read more about Azure Functions here.

How do Automation tasks differ from Azure Automation and Azure Functions?

Automation tasks and Azure Functions are more basic and lightweight than Azure Automation. Currently, you can create an automation task only at the Azure resource level. Behind the scenes, an automation task is a logic app resource that runs a workflow and is powered by the multi-tenant Azure Logic Apps service. To use Automation tasks, you need to have an Office 365 account to connect, however, this is not the case with Azure Functions and Azure Automation.

By comparison, Azure Automation is a cloud-based automation and configuration service that supports consistent management across your Azure and non-Azure environments. The service comprises process automation for orchestrating processes by using Runbooks, configuration management with change tracking and inventory, update management for your virtual machines, shared capabilities, and heterogeneous features. An automation account gives you complete control during deployment, operations, and decommissioning of workloads and resources.

In terms of scalability, Azure Functions is more scalable than the Automation task which is configured individually at the Azure resource level that you want to automate, and if you have different schedules that you want to trigger based on, then Azure Automation is not scalable too. With Functions, you write only the code once that truly matters to your business and scale faster.

On the pricing side, I would say that the price for Azure Functions is the cheapest option than using Automation tasks or Azure Automation. The functions app is cheaper when compared to the logic app which is the automation engine behind Automation tasks. When comparing Logic Apps and Azure Functions, both can run under a consumption plan. That means both have a pay-per-usage billing model. I will suggest using the pricing calculator here to compare what would be cheaper between the two options. But if you have high resource utilization then the function will be cheaper than a logic app. Please review the serverless comparison here.

The winner is Azure Functions in terms of scalability, easy to manage for a large number of resources, and cheaper… Read on!

Prerequisites

To follow this article, you need to have the following:

1) Azure subscription – If you don’t have an Azure subscription, you can create a free one here.

2) Azure Resource Group (RG).

3) Function App with App Service plan consumption-based (more on this in the next section).

4) Enable system-assigned managed identity for the Function App and assign the right permissions on the desired subscription(s) or management group(s) (more on this in the next section).

5) At least one Azure virtual machine is deployed in the desired RG. Please check the following quickstart guide to create a Linux or Windows virtual machine.

  • Set the appropriate Tag name and Tag value on the target virtual machine that you want to schedule for auto-shutdown and auto-start (more on this in the next section).

Assuming you have all the prerequisites in place, take now the following steps:

Create Function App

In this section, we’ll create a new function app.

Browse to the Azure Portal and then click Create a resource, select Function App.

Select your desired subscription, and resource group, and give it a nice name, such as “stop-start-azvm“.

The runtime stack means what language we would like to write the Function logic. Azure Function provides support for mainstream languages or platforms such as .NET, Java, Node.js, Python, Custom Handler, and PowerShell Core.

For this scenario, we need to choose PowerShell Core as shown in the figure below. We can only choose version 7 which is the latest version at the time of this writing.

Choose your desired Azure region, and then click Next: Hosting > to continue.

Azure Create Function App
Azure Create Function App

Next, we have to create a new or select an existing Storage account, which is required by the latest version of Azure Function V3.

For Plan type, select ‘Consumption‘ for serverless and event-driven scaling for the lowest minimum cost, this Plan is billed dynamically according to your usage, which helps save money when the usage is small as in this case.

As a side note, the ‘Premium‘ is for enterprise-level, serverless applications with event-based scaling and network isolation, or the ‘App Service Plan‘ for reusing compute from the existing app service plan.

Click Next: Monitoring > to continue.

Azure Function Hosting
Azure Function Hosting

On the Monitoring tab, Application Insights can be used to monitor the running health of the function, and can also be used as a console output capture when debugging the function. It’s up to you to decide to enable it or not. In this scenario, I won’t enable it.

Click Review + Create > to review your input, and then select Create.

Azure Function Monitoring
Azure Function Monitoring

After the creation is completed, we need to configure permissions for this Function App to access our virtual machines which could be deployed across multiple subscriptions.

Open your Function App, and then select Identity under the Settings menu, turn on the System assigned toggle to On, then click Save as shown in the figure below, and then confirm by selecting Yes.

Once the system-assigned managed identity is enabled, the Function App resource will be registered with Azure Active Directory (Azure AD). After it’s registered, we can control its access to other services like storage accounts, subscriptions, management groups, etc.

Enable system-assigned managed identity
Enable system-assigned managed identity

Now depending on the scope and coverage that you want to give access to the Function App to stop and start your virtual machines. You can give access to a single VM, resource group(s), subscription(s), or management group(s).

In this example, I will give access to my root management group where I have all my subscriptions organized. You need to select your desired scope, then go to Access control (IAM), select Role assignments and then Click + Add | Add role assignment.

Under “Assign access to” choose Function App, search for the Function App name we just created, then add it as a “Virtual Machine Contributor” role as shown in the figure below, and then click Save. The Virtual Machine Contributor role has enough privilege to stop and start the virtual machines.

Add role assignment
Add role assignment

Please note that we need to give that Function App to stop and start VM permission only and not more, please do not give Owner or Contributor role. Always make sure to follow the principle of the least privilege.

Function Code and Trigger

Now we have our Function App up and running, let’s create a new Function.

From the Functions blade under Functions, select + Create to create a Function as shown in the figure below.

Create new function
Create new function

Next, select “Time trigger” as shown in the figure below, and then click Create.

Timer trigger
Timer trigger

After the function is created, go to Integration and then select Time (Timer) under Trigger as shown in the figure below.

Integration Timer
Integration Timer

Next, enter the CRON expression of the timing logic in the “Schedule” field as shown in the figure below. Take 0 0 * * * 1-6 as an example. This means that the function will trigger from Monday to Saturday, every hour (hourly). Click Save.

Set schedule trigger
Set schedule trigger

As a reference, here is the basic format of the CRON expressions in Azure Functions:

{second} {minute} {hour} {day} {month} {day of the week}

e.g. 0 * * * * * (is equal to every minute).

The following values are allowed for the different placeholders:

ValueAllowed ValuesDescription
{second}0-59; *{second} when the trigger will be fired
{minute}0-59; *{minute} when the trigger will be fired
{hour}0-23; *{hour} when the trigger will be fired
{day}1-31; *{day} when the trigger will be fired
{month}1-12; *{month} when the trigger will be fired
{day of the week}0-6; MON-SUN; *{day of the week} when the trigger will be fired

For more information about Azure Functions time trigger, please refer to the official documentation here.

Please keep in mind that the trigger executes at UTC time. So for Bern (UTC+1), a trigger at 18:00 (UTC) executes at 19:00 Switzerland (UTC+1) wintertime and 20:00 (UTC+2) summertime. You will see later in the PowerShell code how we convert the UTC time zone to make sure that we AutoShutdown and AutoStart the VM based on “West Europe Standard Time” and not UTC.

Next, go to Code + Test of the function, and replace the default PowerShell code for run.ps1 with the below code. Please make sure to replace the $subscriptionids variable values with your Azure subscription(s) information.

# Input bindings are passed in via param block.
param($Timer)

# Add all your Azure Subscription Ids below
$subscriptionids = @"
[
    "aaaaaaaa-1234-5678-0000-999999999999",
    "bbbbbbbb-1234-5678-0000-999999999999",
    "cccccccc-1234-5678-0000-999999999999",
    "dddddddd-1234-5678-0000-999999999999",
    "eeeeeeee-1234-5678-0000-999999999999",
    "ffffffff-1234-5678-0000-999999999999",
    "gggggggg-1234-5678-0000-999999999999",
    "hhhhhhhh-1234-5678-0000-999999999999",
    "iiiiiiii-1234-5678-0000-999999999999",
    "jjjjjjjj-1234-5678-0000-999999999999"
]
"@ | ConvertFrom-Json

# Convert UTC to West Europe Standard Time zone
$date = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([DateTime]::Now,"W. Europe Standard Time")

foreach ($subscriptionid in $subscriptionids) {
# Selecting Azure Sub
Set-AzContext -SubscriptionId $SubscriptionID | Out-Null

$CurrentSub = (Get-AzContext).Subscription.Id
If ($CurrentSub -ne $SubscriptionID) {
Throw "Could not switch to SubscriptionID: $SubscriptionID"
}

$vms = Get-AzVM -Status | Where-Object {($_.tags.AutoShutdown -ne $null) -and ($_.tags.AutoStart -ne $null)}
$now = $date

foreach ($vm in $vms) {

if (($vm.PowerState -eq 'VM running') -and ($now -gt $(get-date $($vm.tags.AutoShutdown))) ) {
    Stop-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Confirm:$false -Force
    Write-Warning "Stop VM - $($vm.Name)"
}
elseif (($vm.PowerState -ne 'VM running') -and ($now -gt $(get-date $($vm.tags.AutoStart))) -and ($now -lt $(get-date $($vm.tags.AutoShutdown))) ) {
    Start-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName
    Write-Warning "Start VM - $($vm.Name)"
}

}
}

Although param($Timer) in the script above is not used in the code logic, however, it cannot be deleted. This is a required parameter of Timer Trigger.

The Set-AzContext, Get-AzVM, Start-AzVM, and Stop-AzVM cmdlets are not PowerShell modules, they are from the Azure (Az) PowerShell module. Since Azure PowerShell is already installed on the Function host, those commands can be used directly (more on this in a bit).

Click Save to save your code.

Function PowerShell Code
Function PowerShell Code

Now before we test our code, we need to enable the Az PowerShell module on the Function App under the App Service Editor.

From the Functions blade under Development Tools, select App Service Editor (Preview), and then click on Go-> as shown in the figure below.

App Service Editor
App Service Editor

A new browser tab will open where you can edit the requirements for the Function host.

As shown in the figure below, select requirements.psd1 and uncomment the ‘Az’ = ‘6.*’ on line number 7. This is a very important step, otherwise, the function won’t be able to use the Az module, thus the PowerShell code will fail to run.

Enable the use of Az Module in your function app
Enable the use of Az Module in your function app

Close the App Service Editor tab.

Set Tags for Azure VMs

The final step is to set the Tag names and Tag values on the desired virtual machine(s) that you want to schedule for AutoShutdown and AutoStart.

There are multiple ways how to set and create tags for your Azure resources. In this example, I will show you two options by using the Azure Portal and the Azure PowerShell.

Navigate to your virtual machine in the Azure Portal, on the Overview page, select (change) next to Tags.

As shown in the figure below, enter the Tag names and adjust the value(s) based on your desired schedule. Please make sure the Tag names are entered correctly (AutoShutdown and AutoStart), otherwise, the function won’t work.

In this example, the AutoShutdown is set to 20:00 at night, and AutoStart is set to 07:00 in the morning.

Set tags on Azure VM
Set tags on Azure VM

The good news is, based on the values set on the tags, the Function will automate the stop and start for the VM.

Please note that you can have different values (times) on different virtual machines, and since the function will trigger hourly, it will stop and start the VM based on the values you enter here.

What about if you want to stop and start the VM at half past the hour? In this case, we need to decrease the time trigger and run the function every 30 minutes instead of every hour.

Now if you have many VMs you want to automate this process, we could use the Azure PowerShell to tag our VMs.

Assuming you already have some Tags assigned on your Azure virtual machines, the PowerShell commands below will only add additional tags called AutoShutdown and AutoStart with their respective values “20:00” and “07:00”. For the VMs variable, please replace the “rgname“, and “vmname” with your Azure information.

$vms = @"
[
    {
        "rgname": "resource-group1",
        "vmname": "vm1"
    },
    {
        "rgname": "resource-group2",
        "vmname": "vm2"
    },
    {
        "rgname": "resource-group3",
        "vmname": "vm3"
    }
]
"@ | ConvertFrom-Json

foreach ($vm in $vms) {
    $tags = (Get-AzResource -ResourceGroupName $vm.rgname -Name $vm.vmname).Tags
    $tags += @{ AutoShutdown = "20:00";  AutoStart = "07:00" }
    Set-AzResource -ResourceGroupName $vm.rgname -Name $vm.vmname -ResourceType "Microsoft.Compute/VirtualMachines" -Tag $tags
}

If you want to tag a virtual machine using the Azure CLI, please see how to tag a virtual machine in Azure using the Azure CLI.

Test the Schedule

At this step, we are ready to test our function.

First, you need to change the tag values for AutoShutdown and AutoStart for a VM to a closer hour depending on what time you created the function.

Next, you can trigger the function manually by going to the Function App, selecting your function, then going to Code + Test, clicking “Test/Run” and clicking Run. If everything is OK you should not see any error in the Logs console as shown in the figure below and now your VM should be stopped or started.

Test and Run
Test and Run

The next option is to simply wait for the next hour when the function will automatically trigger.

If we look at the Activity log for the VM, we can see that schedule worked successfully and the VM was turned off at 20:00 and started at 07:00 in the morning. The event was automatically initiated by the Function App name.

Azure VM Activity log
Azure VM Activity log

That’s there you have it!

Summary

In this article, I showed you how to create an Azure Function so you can schedule the start and stop of your Azure virtual machines based on the defined Tag names and values. This will help you to save costs and you only pay for virtual machines when you’re running them.

With Azure Functions, you can build more scalable and stable event-driven applications with a microservices-friendly approach using Functions. Please refer to the pricing pages below for more details:

Logic App Pricing: https://azure.microsoft.com/en-us/pricing/details/logic-apps/

Function App Pricing: https://azure.microsoft.com/en-us/pricing/details/functions/

Azure Automation Pricing: https://azure.microsoft.com/en-us/pricing/details/automation/

As a monthly bonus for the consumption plan pricing, both Azure Functions, and Logic Apps include a monthly free grant* (the First 4,000 actions free for logic apps and 400,000 GB-s for functions).

*Free grants apply to paid, consumption subscriptions only. In that scenario, you can leverage the Azure function to automate and schedule the start and stop of your Azure virtual rather than using a logic app (automation tasks) if it is under the free limit.

__
Thank you for reading my blog.

If you have any questions or feedback, please leave a comment.

-Charbel Nemnom-

Related Posts

Previous

Passing the Azure Security Center Ninja Training

Migrating Your Video Pipeline to Azure Media Services

Next

19 thoughts on “Schedule Start/Stop for Azure VM with Azure Function”

Leave a comment...

  1. Thank you for supplying the logic for the start and stop of VMs. Unfortunately, it appears your logic does not work if you try to stop and start a VM where both the times are either in AM or both the times are in PM. For example, if you schedule to stop a VM at 13:00 and restart at 20:00, the VM will be stopped but it will never be restarted. This is because your logic requires that not only the AutoStart time be greater than the current time, but also the current time be less than the AutoShutdown time. Following this example, if the current time is 20:15, the condition that the current time is greater than AutoStart will be satisfied, however, the current time will never be less than the AutoShutdown time. As you can see, this condition will not ever be met and the VM will never be restarted. I think the logic needs to be adjusted to account for this condition.

  2. Hello Tim, thank you for the comment, feedback, and testing the logic for the start and stop of VMs!
    I have updated the logic in PowerShell to meet both conditions where the time could be either in AM or both the times are in PM.
    Could you please confirm if it’s working for you now?
    Thanks!

  3. I would be happy to test the modified solution if you can provide the modified code. I do not see it in code supplied on this page. It seems to be the same as before.

    Thanks,
    Tim

  4. The modified code will also not work. You have created an infinite loop of turning on and off the VM every time the function fires. I have included my modifications to get it to work correctly and allowed for a 5 minutes buffer for the conditional statements to be evaluated since it could take some time if the list of subscriptions is very large. I have not tested this exhaustively but it does work for the most common cases I could think of. Let me know what you think.

    foreach ($vm in $vms) {
    #To handle the situations where both stop and start are in the AM or PM, we need to get the correct compare value
    $adddatevalue = ($(get-date $($vm.tags.AutoShutdown)))+($(get-date $($vm.tags.AutoStart))-$(get-date $($vm.tags.AutoShutdown)))

    #Adding a 5 minutes window to do a rough comparison of time to account for system latency
    $adddatevalue = $adddatevalue.AddSeconds(300)

    if (($vm.PowerState -eq ‘VM running’) -and ( $now -gt $(get-date $($vm.tags.AutoShutdown)) ) -and ($now -lt $(get-date $($vm.tags.AutoStart))))
    {
    Stop-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Confirm:$false -Force
    Write-Warning “Stop VM – $($vm.Name)”
    }
    elseif (($vm.PowerState -ne ‘VM running’) -and ($now -ge $(get-date $($vm.tags.AutoStart)) ) -and (($now -lt $(get-date $($vm.tags.AutoShutdown))) -or ($now -le $adddatevalue)))
    {
    Start-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName
    Write-Warning “Start VM – $($vm.Name)”
    }
    else {
    Write-Warning “No conditions met to start or stop a VM”
    }
    }
    }

  5. Hello Tim, thanks for sending the updated code!

    I didn’t understand why the modified code will create an infinite loop of turning on and off the VM every time the function fires.
    I have tested it exhaustively in production for the three different scenarios (both times are in AM, both times are in PM, one time in AM, and the second time in PM).
    The machine is turning Off (1 time) and On (1 time) based on the time set in the Tag:
    AutoStart
    AutoShutdown

    This is the code I am running as of today:

    foreach ($vm in $vms) {
    
    if (($vm.PowerState -eq 'VM running') -and ( $now -gt $(get-date $($vm.tags.AutoShutdown))) ) {
        Stop-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Confirm:$false -Force
        Write-Warning "Stop VM - $($vm.Name)"
    }
    elseif (($vm.PowerState -ne 'VM running') -and ( $now -gt $(get-date $($vm.tags.AutoStart))) ) {
        Start-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName
        Write-Warning "Start VM - $($vm.Name)"
    }
    
    }

    I am converting the date and time (now) before checking the status with the if statement:

    $date = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([DateTime]::Now,"W. Europe Standard Time")
    $now = $date

    Could you please retest it from your side? If I missed something, please let me know.
    Thanks!

  6. I may not have time to test today but let me explain. If the autoshutdown time is set to 11:00 and autostart set to 12:00, and let’s say the machine is currently running. Now let’s say the current time is 11:01 and the function fires. Based on your logic of the machine currently running, and the current time greater than the shutdown time, the machine will shutdown. Now let’s say the time moves forward and it’s now 12:01 pm. Based on your logic of the machine not running and current time greater than the autostart time, the machine will be powered on. All is good so far. Now the function fires again let’s say at 13:00. Based on the logic, the machine is running and the time of 13:00 is greater than the autoshutdown time of 11:00, so the machine will just shutdown again. Then the function fires again at 14:00. The logic for autostart will see the machine is currently not running and the current time is greater than the autostart of 12:00, so the machine will be restarted. This will go on exhaustively. Does this make sense to you? Am I missing something regarding the logic?

  7. Thank you, Tim, now I understood the scenario you are referring to.
    In the example you mentioned, you set the autoshutdown time to 11:00, and autostart is set to 12:00. In my case, I always have the autostart time set before the autoshutdown time.
    Example: The autostart is set to 08:00 and the autoshutdown time is set to 12:00 or later at night. Thus, I did not experience the loop of shutting down and restarting.
    My question is, why the user would have the autoshutdown time set before the autostart? Usually, it’s the opposite. I know that scenario is valid, but I am curious to know about the use case.
    I will add the code you shared to have an extra check for (greater than) and (less than) when the VM is running and when the VM is not running.
    Thank you again.

  8. The use case I am referring to is focused on handling geographic teams working in different time zones. For instance, in the US, we may turn off our VM at 17:00 because our workday is over. But the QA team in India is coming back online at 23:00 because that is the start of their day. So in this case, the shutdown time is before the autostart time. And since there is overlap between the end of the India workday and the beginning of the US workday, the machine is left running until the US workday ends.

    As for your example, I believe it too will experience the same issue. If the autostart is 0800 and the shutdown is 1400, when the function runs at 1400, the logic will shut down the VM. When it runs again at 1500, the logic for autostart will become true again because the VM is not running, and the current time of 1500 is greater than the autostart time of 0800. This cycle will continue. I am not sure why your testing was not able to reproduce this scenario. Anyway, I just wanted to help make this a better solution, which was already very good, easy to implement and maintain, and very easy for the end-user to control with just tags. Thank you.

  9. Thank you Tim for sharing the use case. That’s really helpful!
    For my example, I never came across this issue where the autostart is 08:00 and the shutdown is 14:00. I had it running for more than 2 months.
    Thank you for this improvement and all the best!
    Cheers,

  10. Hi,

    Recognizing this article is a little dated I am hoping you still notice this comment and may be able to provide some guidance.

    This is code is exactly what I am looking for – the ability the auto-start and auto-shutdown VMs based on tag variables.

    However, using the code provided here, unfortunately, results in inconsistent behavior. More often than not the startup or shutdown routine does not work based on the trigger schedule, or at all, even though running test code appears successful.

    Really hoping you may be able to share some insights?

  11. Hello CW, thanks for the comment and for sharing your experience!
    Please note that I have updated the code, could you please copy it again and try it?
    Let me know if it works for you now.

  12. Charbel it’s a great guide, exactly what I was looking for. Within this same function and code, is it possible to check if there is a user with active sessions on the server? Or do I have to do an invoke command? Because if so, I won’t shut down that server. I’m not referring to logged-in users but disconnected, only active users. Thank you,

  13. Hello Carlos, thanks for the feedback and comment!
    I am glad to hear that it works for you.
    To answer your question, we can’t check if there are users with active sessions on the server without doing an invoke session.
    You need to build on top of this function and check each server individually and take the correction to shut down or bypass.
    Hope it helps.

  14. Hi again, it’s Tim.
    I think I have discovered another scenario that is not working quite the way I think it should. I have a team working in IST time. The start and stop times are in UTC. So in my case, the shutdown time is set to 16:30 UTC and the start time of 02:30 UTC. The machine is running. Let’s say the current UTC time is 21:30. The function fires. Since the machine is running, the logic is checked to see if the shutdown time is greater than the current time, which is true. Then it checks to see if the current time is less than the start time, which it is not. That portion of the if statement will be false until 00:01. This means that I will only shut down the VM for over two hours and then it will start again. Then when the function fires again at 16:30 UTC, we will face the same issue. The shutdown time will not be less than the start time for many hours later. What is the reason for checking against the start time?

    Thanks,
    Tim

  15. Hello Tim, thanks for the feedback and follow-up!
    What I would suggest is to try the original code published in this article.
    I have also noticed that the updated code that you shared and discussed before is not working in all scenarios.
    NOTE: Make sure to put the AutoStart and AutoShutdown Tags based on the local time in the desired country (IST, PST, CET, etc.).
    Forget about UTC, the code is converting to the local time (i.e West Europe Standard Time) to match the Tag that I set for all my VMs running in Europe.
    In your case, you can add a new Tag to define the Region or Timezone you want.
    You can update this line with an IF statement to convert to IST or PST to tackle all VMs in any time zone.

    #Convert UTC to West Europe Standard Time zone
    $date = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([DateTime]::Now,"W. Europe Standard Time")

    I strongly believe the original code will work in any scenario.
    Thanks!

  16. Thank you for responding, and for your suggestions. I omitted to tell you that I changed the $date line to convert the current time to UTC. And I am having my VM owners enter the tag values in UTC. That way I don’t have to worry about what time zone they are in. I will figure out a way to fix the issue I surfaced. Thanks.

  17. Thank you, Tim, I am glad to hear that the issue is resolved now!
    I was pretty sure that the issue was about time zone conversion.
    Best,

Let me know what you think, or ask a question...

error: Alert: The content of this website is copyrighted from being plagiarized! You can copy from the 'Code Blocks' in 'Black' by selecting the Code. Thank You!