Search code examples
azurepowershellazure-vm-role

Find if Azure VM has been idle


I am looking for way to find if Azure VM has been idle for over an hour. The criteria to qualify for idle if there is no mouse movement for over an hour. I want to save the State of VM and shut it down.

Can this be achieved using Powershell comands ?


Solution

  • I have configured something similar in the past, and unfortunately the only reliable way of doing this, was via a Task Scheduled on Windows (you don't specify OS in your original question). Now the following code which you should execute in PowerShell will:

    1. If there is no activity for past 30 minutes, it will trigger a shutdown command with another 60 seconds to give user time to perform any action in order to cancel it and wait for the next triggering period. Notice the switch RunOnlyIfIdle
    2. Start checking at 8PM for the next 12 hours every 1 hour whether there was any activity on the machine (including clicks, mouse moves, etc.), it excludes the system processes as it is build to do exactly this
    3. RunLevel is set to 1, so OS has permissions to execute the task with no regards to the fact whether the user is still logged in or not
    4. As you can see two last lines actually create the scheduled task, and it is configured to create it under the context of currently logged in user which executed the script, but can be adjusted if necessary

    Now this will only shut down the OS, but the VM resource in Azure will only reach "Stopped" state, thus still charging you money for the compute power. In order to get it to "Stopped (Deallocated)" state and stop charging you, I had an Automation Account in Azure which had a script that was scheduled to execute every hour and scan all VMs with state "Stopped" and then it executed the command Az-StopVM which actually deallocated the VM and stopped charging money.

    $TaskName = 'Idle_Shutdown'
    
    $Service = New-Object -ComObject('Schedule.Service')
    $Service.Connect()
    $RootFolder = $Service.GetFolder('')
    
    $TaskDefinition = $Service.NewTask(0)
    
    $Settings = $TaskDefinition.Settings
    $Settings.AllowDemandStart = $true
    $Settings.Compatibility = 2
    $Settings.Enabled = $true
    $Settings.RunOnlyIfIdle = $true
    $Settings.IdleSettings.IdleDuration = 'PT30M'
    $Settings.IdleSettings.WaitTimeout = 'PT5M'
    $Settings.IdleSettings.StopOnIdleEnd = $true
    
    $Trigger = $TaskDefinition.Triggers.Create(2)
    $Trigger.Repetition.Interval = 'PT1H'
    $Trigger.Repetition.Duration = 'PT12H'
    $Trigger.StartBoundary = ([datetime]::Now).ToString("yyyy-MM-dd'T'20:00:00")
    $Trigger.Enabled = $true
    
    $Action = $TaskDefinition.Actions.Create(0)
    $Action.Path = 'shutdown'
    $Action.Arguments = '/s /t 60'
    
    $LocalUser = $TaskDefinition.Principal
    $LocalUser.RunLevel = '1'
    
    $user = [environment]::UserDomainName + '\' + [environment]::UserName
    $null = $RootFolder.RegisterTaskDefinition($TaskName, $TaskDefinition, 6, $user, $null, 2)