Tutorial: Create pre and post events using Azure Functions

Applies to: ✔️ Windows VMs ✔️ Linux VMs ✔️ On-premises environment ✔️ Azure VMs ✔️ Azure Arc-enabled servers.

This tutorial explains how to create pre and post events to start and stop a VM in a schedule patch workflow using Azure Functions.

In this tutorial, you learn how to:

  • Prerequisites
  • Create a function app
  • Create a function
  • Create an event subscription

Prerequisites

  1. Ensure that you are using PowerShell 7.2 runbook.

  2. Assign permission to managed identities - You can assign permissions to the appropriate managed identity. The runbook can use either the Automation account system-assigned managed identity or a user-assigned managed identity.

    You can use either portal or PowerShell cmdlets to assign permissions to each identity:

    Follow the steps in Assign Azure roles using the Azure portal to assign permissions


  1. Import the Az.ResourceGraph module, ensure the module is updated to ThreadJob with the module version 2.0.3.

Create a function app

  1. Follow the steps to Create a function app.

  2. After you create the function app, Go to resource, ensure that you load the dependencies by following these steps:

    Note

    You have to load the dependencies only for the first time. If the PowerShell dependencies are failing to load. Check the latest versions of AZ, and AZ.ResourceGraph.

    1. On the Function App, select App files.

    2. Under the host.json, enable ManagedDependecy to True and select requirements.psd1.

    3. Under the requirements.psd1, paste the following code:

       @{
       'Az'='12.*' 
       'Az.ResourceGraph'='1.0.0' 
       'Az.Resources'='6.*' 
       'ThreadJob' = '2.*'
       }
      
    4. Select Save.

  3. Restart the function app from the Overview tab to load the dependencies that are mentioned in the requirements.psd1 file.

Create a function

  1. After you create the function app, go to Resource, and in Overview, select Create in Azure portal.

  2. In the Create function window, make the following selections:

    1. For the Development environment property, select Develop in portal
    2. In Select a template, select Event Grid.
    3. In Template details, enter the name in New Function and then select Create. Screenshot that shows the options to select while creating a function.
  3. In the Event grid function, select Code+Test from the left menu, paste the following code and select Save.

    # Make sure that we are using eventGridEvent for parameter binding in Azure function.
    param($eventGridEvent, $TriggerMetadata)
    
    Connect-AzAccount -Identity
    
    # Install the Resource Graph module from PowerShell Gallery
    # Install-Module -Name Az.ResourceGraph
    
    $maintenanceRunId = $eventGridEvent.data.CorrelationId
    $resourceSubscriptionIds = $eventGridEvent.data.ResourceSubscriptionIds
    
    if ($resourceSubscriptionIds.Count -eq 0) {
        Write-Output "Resource subscriptions are not present."
        break
    }
    
    Write-Output "Querying ARG to get machine details [MaintenanceRunId=$maintenanceRunId][ResourceSubscriptionIdsCount=$($resourceSubscriptionIds.Count)]"
    
    $argQuery = @"
        maintenanceresources 
        | where type =~ 'microsoft.maintenance/applyupdates'
        | where properties.correlationId =~ '$($maintenanceRunId)'
        | where id has '/providers/microsoft.compute/virtualmachines/'
        | project id, resourceId = tostring(properties.resourceId)
        | order by id asc
    "@
    
    Write-Output "Arg Query Used: $argQuery"
    
    $allMachines = [System.Collections.ArrayList]@()
    $skipToken = $null
    
    do
    {
        $res = Search-AzGraph -Query $argQuery -First 1000 -SkipToken $skipToken -Subscription $resourceSubscriptionIds
        $skipToken = $res.SkipToken
        $allMachines.AddRange($res.Data)
    } while ($skipToken -ne $null -and $skipToken.Length -ne 0)
    if ($allMachines.Count -eq 0) {
        Write-Output "No Machines were found."
        break
    }
    
    $jobIDs= New-Object System.Collections.Generic.List[System.Object]
    $startableStates = "stopped" , "stopping", "deallocated", "deallocating"
    
    $allMachines | ForEach-Object {
        $vmId =  $_.resourceId
    
        $split = $vmId -split "/";
        $subscriptionId = $split[2]; 
        $rg = $split[4];
        $name = $split[8];
    
        Write-Output ("Subscription Id: " + $subscriptionId)
    
        $mute = Set-AzContext -Subscription $subscriptionId
        $vm = Get-AzVM -ResourceGroupName $rg -Name $name -Status -DefaultProfile $mute
    
        $state = ($vm.Statuses[1].DisplayStatus -split " ")[1]
        if($state -in $startableStates) {
            Write-Output "Starting '$($name)' ..."
    
            $newJob = Start-ThreadJob -ScriptBlock { param($resource, $vmname, $sub) $context = Set-AzContext -Subscription $sub; Start-AzVM -ResourceGroupName $resource -Name $vmname -DefaultProfile $context} -ArgumentList $rg, $name, $subscriptionId
            $jobIDs.Add($newJob.Id)
        } else {
            Write-Output ($name + ": no action taken. State: " + $state) 
        }
    }
    
    $jobsList = $jobIDs.ToArray()
    if ($jobsList)
    {
        Write-Output "Waiting for machines to finish starting..."
        Wait-Job -Id $jobsList
    }
    
    foreach($id in $jobsList)
    {
        $job = Get-Job -Id $id
        if ($job.Error)
        {
            Write-Output $job.Error
        }
    }
    
  4. Select Integration from the left menu and edit the Event Trigger parameter name under Trigger. Use the same parameter name given in the Code+Test window. In the example, the parameter is eventGridEvent.

    Screenshot that shows the parameter eventGridEvent.

  5. Select Save

Create an Event subscription

  1. Sign in to the Azure portal and go to your Azure Update Manager.
  2. Under Manage, select Machines, Maintenance Configuration.
  3. On the Maintenance Configuration page, select the configuration.
  4. Under Settings, select Events.
  5. Select +Event Subscription to create a pre/post maintenance event.
  6. On the Create Event Subscription page, enter the following details:
    1. In the Event Subscription Details section, provide an appropriate name.
    2. Keep the schema as Event Grid Schema.
    3. In the Event Types section, Filter to Event Types.
      1. Select Pre Maintenance Event for a pre-event.
        • In the Endpoint details section, select the Azure Function endpoint and select Configure and Endpoint.
        • Provide the appropriate details such as Resource groups, function app to trigger the event.
      2. Select Post Maintenance Event for a post-event.
        • In the Endpoint details section, the Azure Function endpoint and select Configure and Endpoint.
        • Provide the appropriate details such as Resource group, Function app to trigger the event.
  7. Select Create.

You can also use Azure Storage accounts and Event hub to store, send, and receive events. Learn more on how to create Event hub and Storage queues.

Next steps