Switch off Virtual Machines on a schedule using an Azure Tag by info.odysseyx@gmail.com August 23, 2024 written by info.odysseyx@gmail.com August 23, 2024 0 comment 14 views 14 1. Introduction Managing the costs of running virtual machines (VMs) in Azure can be challenging, especially when VMs are running during non-business hours. One effective solution is to use Azure tags to schedule automatic shutdowns. In this blog, we will walk you through a PowerShell script that uses Azure tags to define and enforce a VM shutdown schedule. 2. Prerequisites Before you begin, make sure you have the following: An activated Azure subscription. Appropriate permissions to manage VMs and read tag information. Basic knowledge of PowerShell scripting. 3. Script Overview The script manages the power state of Azure virtual machines based on the specified tags and their values, which define a schedule. For example, a tag called “AutoShutdownSchedule” with a value of “10PM -> 6AM” will shut down the VM at 10PM and start it at 6AM. 4. Detailed script analysis Parameters and Initial Settings The script accepts three parameters: TagName: The name of the tag to find in the virtual machine. ManagementGroupId: The ID of the Azure management group to work with. Simulate: If set $trueThe script only simulates the action without making any changes. param ( [parameter(Mandatory = $true)] [string]$TagName, [parameter(Mandatory = $true)] [string]$ManagementGroupId, [parameter(Mandatory = $false)] [bool]$Simulate = $false ) Function: Get-SubscriptionsUnderManagementGroup This function retrieves all subscription IDs that belong to the specified Azure management group. function Get-SubscriptionsUnderManagementGroup { param ( [Parameter(Mandatory = $true)] [string]$ManagementGroupId ) # Array to store subscription IDs $subscriptionIds = @() # Get the management group hierarchy $managementGroup = Get-AzManagementGroup -GroupId $ManagementGroupId -Expand if ($managementGroup -and $managementGroup.Children) { # Loop through each child in the management group foreach ($child in $managementGroup.Children) { if ($child.Type -eq "Microsoft.Management/managementGroups") { # Recursively get subscriptions from child management groups $childManagementGroupId = $child.Name $subscriptionIds += Get-SubscriptionsUnderManagementGroup -ManagementGroupId $childManagementGroupId } elseif ($child.Type -match "/subscriptions") { # Extract subscription ID $subscriptionId = [regex]::Match($child.Name, "([a-f0-9-]{36})").Value if ($subscriptionId) { $subscriptionIds += $subscriptionId } } } } return $subscriptionIds } Function: CheckScheduleEntry This function checks whether the current time is within a specified time range. function CheckScheduleEntry ([string]$TimeRange) { $rangeStart, $rangeEnd, $parsedDay = $null $currentTime = (Get-Date).ToUniversalTime().AddHours(2) $midnight = $currentTime.AddDays(1).Date try { if ($TimeRange -like "*->*") { $timeRangeComponents = $TimeRange -split "->" | ForEach-Object { $_.Trim() } if ($timeRangeComponents.Count -eq 2) { $rangeStart = Get-Date $timeRangeComponents[0] $rangeEnd = Get-Date $timeRangeComponents[1] if ($rangeStart -gt $rangeEnd) { if ($currentTime -ge $rangeStart -and $currentTime -lt $midnight) { $rangeEnd = $rangeEnd.AddDays(1) } else { $rangeStart = $rangeStart.AddDays(-1) } } } else { Write-Output "`WARNING: Invalid time range format. Expects valid .Net DateTime-formatted start time and end time separated by '->'" } } else { if ([System.DayOfWeek].GetEnumValues() -contains $TimeRange) { if ($TimeRange -eq (Get-Date).DayOfWeek) { $parsedDay = Get-Date "00:00" } } else { $parsedDay = Get-Date $TimeRange } if ($parsedDay -ne $null) { $rangeStart = $parsedDay $rangeEnd = $parsedDay.AddHours(23).AddMinutes(59).AddSeconds(59) } } } catch { Write-Output "`WARNING: Exception encountered while parsing time range. Details: $($_.Exception.Message). Check the syntax of entry, e.g. ' -> ', or days/dates like 'Sunday' and 'December 25'" return $false } if ($currentTime -ge $rangeStart -and $currentTime -le $rangeEnd) { return $true } else { return $false } } Function: AssertVirtualMachinePowerState This feature ensures that VMs are in the desired power state (running or stopped) on a scheduled basis. function AssertVirtualMachinePowerState { param ( [Object]$VirtualMachine, [string]$DesiredState, [bool]$Simulate ) $resourceManagerVM = Get-AzVM -ResourceGroupName $VirtualMachine.ResourceGroupName -Name $VirtualMachine.Name -Status $currentStatus = $resourceManagerVM.Statuses | Where-Object { $_.Code -like "PowerState*" } $currentStatus = $currentStatus.Code -replace "PowerState/", "" if ($DesiredState -eq "Started" -and $currentStatus -notmatch "running") { if ($Simulate) { Write-Output "[$($VirtualMachine.Name)]: SIMULATION -- Would have started VM. (No action taken)" } else { Write-Output "[$($VirtualMachine.Name)]: Starting VM" $resourceManagerVM | Start-AzVM } } elseif ($DesiredState -eq "StoppedDeallocated" -and $currentStatus -ne "deallocated") { if ($Simulate) { Write-Output "[$($VirtualMachine.Name)]: SIMULATION -- Would have stopped VM. (No action taken)" } else { Write-Output "[$($VirtualMachine.Name)]: Stopping VM" $resourceManagerVM | Stop-AzVM -Force } } else { Write-Output "[$($VirtualMachine.Name)]: Current power state [$currentStatus] is correct." } } The script iterates through all VMs in a given subscription, checks tags, and applies power states according to a schedule. Here's an overview of what the script does: try { # Main script logic } catch { $errorMessage = $_.Exception.Message throw "Unexpected exception: $errorMessage" } finally { Write-Output "Script finished (Duration: $(("{0:hh\:mm\:ss}" -f ((Get-Date).ToUniversalTime() - $currentTime))))" } 5. Usage examples To run the script, use the following command: .\StartStopVMsBasedOnTag.ps1 -TagName "AutoShutdownSchedule" -ManagementGroupId "MngEnv" -Simulate $true We run the examples in local PowerShell, but PowerShell can run anywhere, including within your Automation account. 5.1 We tag the virtual machines accordingly. 5.2 After you log in to Azure, examine the PowerShell code and run the commands. 5.3 We used the "-Simulate $true" flag to show what would have happened. If you want to run this in production, you can first simulate and then, when you are satisfied with the test, switch "-Simulate $false" to stop the simulation. 6. Conclusion Automating VM shutdown schedules using Azure tags can help you optimize resource usage and reduce costs. Following this guide will help you implement a similar solution in your Azure environment. If you have any questions or feedback, please leave a comment below. A copy of this code can be found in my GitHub Repo --> RallTheory/StartStopVMs/StartStopVMsBasedOnTag.ps1 at main · WernerRall147/RallTheory (github.com) disclaimer The sample script is not supported by any Microsoft standard support program or service. The sample script or Power BI dashboard is provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties, including but not limited to the implied warranties of merchantability or fitness for a particular purpose. The entire risk arising out of the use or performance of the sample script and documentation remains with you. In no event shall Microsoft, the authors, or anyone else involved in the creation, production, or delivery of the script or Power BI dashboard be liable for any damages whatsoever (including but not limited to damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample script or documentation, even if Microsoft has been advised of the possibility of such damages. This blog post was created with the assistance of Generation AI. Source link Share 0 FacebookTwitterPinterestEmail info.odysseyx@gmail.com previous post Just a moment… next post Just a moment… You may also like 7 Disturbing Tech Trends of 2024 December 19, 2024 AI on phones fails to impress Apple, Samsung users: Survey December 18, 2024 Standout technology products of 2024 December 16, 2024 Is Intel Equivalent to Tech Industry 2024 NY Giant? December 12, 2024 Google’s Willow chip marks breakthrough in quantum computing December 11, 2024 Job seekers are targeted in mobile phishing campaigns December 10, 2024 Leave a Comment Cancel Reply Save my name, email, and website in this browser for the next time I comment.