Azure Arc - Onboarding Servers with Group Policy

Azure Arc - Onboarding Servers with Group Policy

As organizations migrate endpoint management to Intune, a common question I get asked is "What do I do with my servers since Intune only supports clients?" Whether you are looking to move away from Active Directory and Group Policy, Microsoft Configuration Manager, or just trying to figure all of this out, Microsoft's path forward for on-prem and non-Azure cloud resources is Azure Arc.

Azure Arc essentially creates a resource identity and management connection in Azure that enables some key capabilities such as update management, policy management, and Defender for Cloud's Security Posture Management and Workload Protections. It also enables deployment of Azure extensions such as the Azure Monitor Agent used to send logs to Sentinel and Defender for Endpoint as part of Defender for Servers.

Now, we could simply onboard all servers into one Resource Group in Azure, but that's essentially making anyone with permissions in Azure a shared admin across all of our servers. Instead, it's important to plan permissions and create separate Resource Groups (and maybe even Subscriptions) based on tiers/services and other needs to separate privileges like you do in Active Directory (right?). The goal of my Arc for Servers posts is to help you understand the process, capabilities, and start your own evaluation. For actual deployment planning, I highly recommend reviewing the docs: Plan and deploy Azure Arc-enabled servers - Azure Arc

Prepare Azure for Arc Onboarding

Azure has a very different way of organizing resources than we are used to with Active Directory. Instead of OU's, resources (like VMs) are placed in Resource Groups, Resource Groups are placed in Subscriptions for billing and management purposes, and we can optionally add Subscriptions to Management Groups to ease management and enforce IAM/policy at a larger scale. We can also apply Azure permissions to individual resources or at any of these levels and have them inherit down the chain :)

I mention this because some things are only available at specific management levels, such as Subscriptions are where we enable Resource Providers (don't worry, this isn't as complicated as it sounds!). Resource providers simply enable the ability to use certain resources/capabilities in a subscription, and we need at least three providers enabled to onboard servers to Arc.

  • Microsoft.HybridCompute (registered by default)
  • Microsoft.GuestConfiguration (registered by default)
  • Microsoft.HybridConnectivity
  • Microsoft.AzureArcData (if you plan to Arc-enable SQL Servers)

To verify or enable these providers, navigate to your Subscription in Azure, scroll down to Resource providers, then search for each of these items and make sure they are registered. If they are not, select them, then click Register.

Next, we need to create a Resource Group to put our servers in. Search for and select Resource Groups, then click Create. Select the Subscription, provide a name for the Resource Group, click Review + create, then click Create.

Next we need to create a Service Principal with the Azure Connected Machine Onboarding role assigned to it. Think of this like a service account that has permission to create Arc objects in Azure, and this ensures strong authentication while avoiding use of an interactive admin account (that is likely overly permissive and breaks the process when that admin leaves the company).

First, search for and select Azure Arc, then click on Service Principals.

Click Add, provide a Name, then either scope to Subscription or Resource group (based on your IAM permission model), select an amount of time until the secret (password) expires, then select the Role of Azure Connected Machine Onboarding, then click Create. Note: While expiration can go up to 2 years, you may want to automate rotating the secret used with the onboarding script instead.

This is the same as creating an App registration, assigning the role, and creating a client secret, but the experience is a little nicer and has you download the secret so you don't forget to copy it down :)

Finally, we need to set up Group Policy to deploy the Connected Machine Agent and onboard to Azure Arc. To download the latest Connected Machine Agent, we can always use To create the GPO and onboarding script, Microsoft provides a nice set of helper scripts in a GitHub repo. Download the latest release here: Azure/ArcEnabledServersGroupPolicy

Next, we need a file share to put the installer and scripts on, and while I generally like to use the NETLOGON share for small installers, a file server or separate share might be better for this one. The DeployGPO.ps1 script will create two folders in the share and set permissions so that reports about failures can be written back to the share. Try to avoid unnecessary AD replication over WAN links ;)

When creating the share, leave Everyone with Full Control (we will remove that after running the script) and add Change/Read permissions for Domain Admins, Domain Controllers, and Domain Computers. Note that NTFS permissions set by the script will ensure Domain Computers can only write logs back to one subfolder, and they will not be able to modify the installer or scripts ;)

Now copy AzureConnectedMachineAgent.msi to the file share, extract the contents from, run PowerShell as Admin, and browse to the files. Modify the following for your environment, and then run it :)

$params = @{
   DomainFQDN = ''
   ReportServerFQDN  = ''
   ArcRemoteShare = 'Arc'
   ServicePrincipalSecret = 'pd8MQ~esDrSqRkocioL.sMLTSnd6a9CS1O4HnboV'
   ServicePrincipalClientId = '5729024f-b07d-4dc6-9e45-3a4ffd092905'
   SubscriptionId = 'a089a09e-bf38-4e1a-a416-27850ba3c276'
   ResourceGroup = 'arc-lab1-westus2'
   Location = 'westus2'
   TenantId = '8c7b5a07-c315-43f4-b1c2-eb1461ad4fab'
.\DeployGPO.ps1 @params

Now would be a good time to remove the Everyone permissions on the share so we don't forget, and then we can review the GPO that was created in the Group Policy management console that was launched. Look for the [MSFT] Azure Arc Servers Onboarding GPO under Group Policy Objects. It should look like this:

As we can see, this creates a couple of registry keys and a couple of Scheduled Tasks, one that deletes an existing Arc install task and one that creates the Arc install task. Since we should always do testing before deployment, create an empty OU somewhere we can safely move a test server or two into and link the Arc GPO:

Now we just need to move a server or two into the Arc testing OU and perform a gpupdate (or reboot). In some cases, I have seen pending restarts allow installation of the agent but require a restart before onboarding is completed. To verify policy, we can look at Task Scheduler and see that our task shows up and ran successfully:

We can also verify installation by looking for Azure Connected Machine Agent in Add/Remove Programs and by looking under C:\Program Files\AzureConnectedMachineAgent (azcmagent.exe provides our config options).

And finally, we can also verify successful onboarding by looking under Azure Arc | Servers in the Azure Portal. Unfortunately, this lab was all I had to work with right now, and I would always advise against starting with Tier 0 systems... :p Either don't onboard Tier 0 or ensure they have a proper privilege separation.


You may remember there was a AzureArcLogging folder in the share that we created, and the scripts will write out to it only when there is a failure condition. As we did above, start with policy and ensure the GPO is applying, the scheduled task shows up, and verify that the agent is being copied to C:\Windows\Temp. The installer saves logs to C:\Windows\Temp, and the script will also output to the AzureArcLogging folder on the share.

If the agent is installing but not onboarding, double check that you see sign-in events for the Service Principal in Azure AD. If you see failures, it's possible the secret has expired and may need to be generated again.

To avoid running DeployGPO.ps1 again just to create the encrypted secret blob, I modified this from the script. Run PowerShell as Admin, browse to the directory where you extracted the ZIP contents with AzureArcDeployment.psm1, modify below with the client secret, and then run to generate a new file. Now replace the encryptedServicePrincipalSecret in the share, and try running the task again.

$ServicePrincipalSecret = 'enter secret value from Azure AD'
$DomainComputersSID = "SID=" + (Get-ADDomain).DomainSID.Value + '-515'
$DomainControllersSID = "SID=" + (Get-ADDomain).DomainSID.Value + '-516'

# Encrypting the ServicePrincipalSecret to be decrypted only by the Domain Controllers and the Domain Computers security groups

$descriptor = @($DomainComputersSID, $DomainControllersSID) -join " OR "

Import-Module .\AzureArcDeployment.psm1
$encryptedSecret = [DpapiNgUtil]::ProtectBase64($descriptor, $ServicePrincipalSecret)

$encryptedSecret | Out-File -FilePath .\encryptedServicePrincipalSecret -Force

To avoid this issue, many orgs will create long lived secrets for use outside of GPO (base templates, OSD, etc.) and update them whenever they rebuild those processes. An alternative option is to automate refreshing the SP secrets, which is actually referenced to in the Microsoft repository, but all go to 404 errors. Hopefully they add these at some point, and I may work on this in the near future.

Security Note: Anyone with administrative rights on a domain joined computer can run a process as SYSTEM to decrypt the credential blob and obtain the secret. The intent of encrypting is to limit exposure, not eliminate it ;)