Assigning Extended Service Updates (ESU) to an Azure ARC enabled Windows Server 2012 via PowerShell/REST

Assigning Extended Service Updates (ESU) to an Azure ARC enabled Windows Server 2012

To automate the ARC server with the ESU updates this may be completed with a PowerShell script calling a REST endpoint. This sample below is assuming that you created the ESU license through the Azure Portal. There is optionally a REST call for the license creation request as well as unlink and delete options in this url link: Programmatically deploy and manage Azure Arc Extended Security Updates licenses – Azure Arc | Microsoft Learn.

Sample script for acquiring the bearer token for the REST call and using this when assigning the ESU license.

NOTE: Ensure that the service principle has the proper RBAC role to the Azure Resource Group (not the subscription) with Contributor or the Azure Connected Machine Onboarding role.

For assistance with the service principle or roles please review this url link: Connect hybrid machines to Azure at scale – Azure Arc | Microsoft Learn

# Define your tenant ID, client ID, and client secret, server is the name of the server to update, esulicensename is from the Azure portal Arc ESU license name, 
# and Azure Region Location.
#
$tenantId = ""
$clientId = ""
$clientSecret = ""
$subscriptionid = ""
$resourcegroup = ""
$server = ""
$esulicensename = ""
$location = ""
#
# Define the resource you want to access
$resource = "https://management.azure.com/"
# Define the token endpoint
$tokenEndpoint = "https://login.microsoftonline.com/$tenantId/oauth2/token"
# Define the body of the request
$body = @{
    'resource' = $resource
    'client_id' = $clientId
    'grant_type' = 'client_credentials'
    'client_secret' = $clientSecret
}
# Invoke the REST method to get the token
$response = Invoke-RestMethod -Method Post -Uri $tokenEndpoint -Body $body
# Extract the token from the response
$token = $response.access_token
# Output the token if needed by uncommenting out the following line
# $token
# Define the Azure API URL
$url = "https://management.azure.com/subscriptions/$subscriptionid/resourceGroups/$resourcegroup/providers/Microsoft.HybridCompute/machines/$server/licenseProfiles/default?api-version=2023-06-20-preview"
# Create headers with the Authorization token
$headers = @{
    "Authorization" = "Bearer $token"
    "Content-Type" = "application/json"
}
$esuBody = @{
    "location" = $location
    "properties" = @{
        "esuProfile" = @{
            "assignedLicense" = "/subscriptions/$subscriptionid/resourceGroups/$resourcegroup/providers/Microsoft.HybridCompute/licenses/$esulicensename"
        }
    }
}
# Convert the request body to JSON format
$bodyJson = $esuBody | ConvertTo-Json
# Make the REST API call
$responseEsu = Invoke-RestMethod -Uri $url -Headers $headers -Method Put -Body $bodyJson
$esuProfile = $responseEsU.properties.esuProfile
$esuProfile

The $esuProfile value will display a similar response as:

assignedLicense : /subscriptions/(your subscription ID)/resourceGroups/(your resource group)/providers/Microsoft.HybridCompute/licenses/(ESU license name)
serverType      : Datacenter
esuEligibility  : Eligible
esuKeyState     : Inactive
esuKeys         : {@{sku=Server-ESU-Year1; licenseStatus=0}, @{sku=Server-ESU-Year2; licenseStatus=0},
                  @{sku=Server-ESU-Year3; licenseStatus=0}}

Note: The esuKeyState value checks to see if a volume license key is installed on the server to avoid double charges for ESU and volume license key. If you are not using volume licensing for ESU this can be ignored

To unlink an ESU from a machine change the $esuBody in the above REST call to this below. Removing the license section to null will set unlink the ESU.

$esuBody = @{
    "location" = $location
    "properties" = @{
        "esuProfile" = @{
        }
    }
}

Below is an Azure Graph Explorer query to show Azure Arc connected and ESU enabled machines.

resources
| where type =~ 'microsoft.hybridcompute/machines' and kind !contains "AVS"
| extend EsuEnabled = properties.licenseProfile.esuProfile.licenseAssignmentState
| extend IsArcConnected = case (
 (type == 'microsoft.hybridcompute/machines'), iff(properties.status == "Connected", 'Enabled', 'Not Enabled'),
"Undefined"
)
| project name, ['ESU Enabled'] = EsuEnabled,IsArcConnected

This will show machines that are “Assigned” which means they are Arc enabled for the ESU license.

To determine if the machine is ESU enabled, on the server that this enablement, check the following areas either in the reg key or existence of the license.json file

  • [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Azure Connected Machine Agent\ArcESU] “Enabled”
    • A value of 1 meaning that a signed doc is present and this machine will receive ESUs. 0 meaning there is no signed doc, and so it is not enabled for Arc based ESUs and won’t receive ESUs via that route. 
  • Alternatively, you can look for the signed doc itself at C:\ProgramData\AzureConnectedMachineAgent\Certs\license.json
A screenshot of a computer

Description automatically generated

About the author

Jeff Pigott is a Senior Cloud Solution Architect at Microsoft, with expertise in Azure technologies such as Arc, DevOps, security, storage, and more. He has over 29 years of experience in IT, development, and DevOps, working with various platforms, tools, and languages. He is passionate about learning the newest Microsoft technologies and services, and holds several Azure certifications.