[ARC 5.1] Build Sheet: Operating an Arc Server

The operations surface in practice: install an extension, wire monitoring with the Azure Monitor Agent, run a PowerShell script on a machine from Azure, open a session with no inbound port, and set the local blocklist that lets a server refuse all of it.


By the end of this you can install and govern an extension, stand up monitoring with the Azure Monitor Agent and a data collection rule, run a PowerShell script on a machine from Azure with Run Command, open a session over the agent with no inbound port, and set the local blocklist that lets a sensitive server refuse all of it. This is the operations surface made concrete, the part where Arc stops being an onboarding story and becomes a way of working. The portal walk comes first, then the same thing as a script, and two of these capabilities are in preview at the time of writing, which the steps call out where it matters.


Before Step 1: Arc-connected machines; the Azure Connected Machine Resource Administrator role for extensions and Run Command; a Log Analytics workspace for the monitoring step; the Azure CLI with its SSH extension, and the Microsoft.HybridConnectivity resource provider registered, for the remote-access step. The agent should be current, because several of these capabilities gained fixes through the 2026 releases, and Microsoft supports only agent versions released in the last year. Read the release notes before you roll a new agent to Windows servers: version 1.68 in September 2026 shipped a port-protection change with a known issue that can block the agent after a reboot, with the fix planned for 1.69, so pilot it on a few machines first. For the remote-access step the server itself must be running an SSH server: sshd on Linux, and the OpenSSH Server service on Windows, which Windows Server 2025 installs by default and earlier versions need added. Check it is running before you blame the tunnel.

Feature status, checked October 2026

Three of the capabilities below are preview features and one is generally available with restrictions, so this sheet dates its claims rather than saying “at the time of writing” and leaving you to guess when that was. Re-check each line before you build a runbook on it.

CapabilityStatus, October 2026What that means for this sheet
Run Command for Arc-enabled servers (Step 3)Public previewCommand line and REST only, no portal path. Treat the interface as unstable even though the capability works
Windows Admin Center in the Azure portal for Arc (end-to-end test)Public previewWorks with no inbound port, but preview terms apply, and enabling it replaces any Windows Admin Center already installed on the machine
Connected Machine agent automatic upgradePublic previewAgent 1.57 and later, Azure public cloud only. Set it at onboarding with --enable-automatic-upgrade on azcmagent connect, which needs agent 1.62 or later, or afterward by setting enableAutomaticUpgrade on the machine or assigning the built-in policy. This is not the same thing as extension automatic upgrade in Step 1, which is generally available
Windows Server 2025 Entra sign-in for Arc (Step 4c)Generally availableGenerally available and still restricted: no Conditional Access support, and enabling it Entra joins the server, which excludes Active Directory domain join
Default guest metrics with no ingestion charge (Step 2)Generally available since June 2026OpenTelemetry guest metrics go to an Azure Monitor workspace and the default set is free. The logs-based path into Log Analytics is still billed as ingestion. Metrics-based collection does not support private link yet, so a private link estate stays on the logs path for now

Step 1: Install an extension, and expect version drift

Extensions are how Arc grows past management into capability, and installing one is the same shape every time. In the portal, open the machine’s Extensions node and add the extension you need, for example the Azure Monitor Agent. The publisher and type must match the extension exactly, which is the one detail people get wrong.

SettingValueWhy
Publisher and typeMust match the extension, e.g. Microsoft.Azure.Monitor / AzureMonitorWindowsAgentA mismatched publisher or type simply fails to install; these are exact product nouns, not descriptions
Automatic upgradeOn by defaultThe right default, and the reason your fleet will run a spread of versions rather than one
Rollout expectationUp to eight weeks for a normal version to reach every machineVersion heterogeneity is the normal state; design monitoring to tolerate it

The same as a script, installing the Azure Monitor Agent on one machine:

az connectedmachine extension create \
  --resource-group "rg-arc-servers" \
  --machine-name "SVR-APP-01" \
  --extension-name "AzureMonitorWindowsAgent" \
  --publisher "Microsoft.Azure.Monitor" \
  --type "AzureMonitorWindowsAgent" \
  --location "eastus"

Expected result: the extension provisions and reports succeeded on the machine’s Extensions node. Failure mode: if your operational model assumes every server runs the same extension build on the same day, it will raise false alarms, because staged rollout guarantees a spread. Plan for heterogeneity rather than chasing it.

Step 2: Turn the agent into monitoring with a data collection rule

Installing the Azure Monitor Agent collects nothing on its own. The agent is the pipe; a data collection rule is what decides what flows through it and where it lands, and until you create one and associate it with the machine, no data moves. In the portal, create a data collection rule that names its data sources, the performance counters and Windows event logs you actually want, and its destination, a Log Analytics workspace, then add the Arc machine as a resource so the association is created.

SettingValueWhy
Data sourcesOnly the counters and logs you will actually useLogs, events and counters sent to Log Analytics are billed as ingestion; a firehose rule is a line item
DestinationA Log Analytics workspaceThe rule routes the data; the workspace is where it is queried and retained
AssociationThe Arc machine added as a resource on the ruleThe association is what actually binds the rule to the machine; without it the agent sits idle

Two cost and direction notes matter here. An Arc server has no free host-level metrics the way an Azure virtual machine does, because there is no hypervisor Azure owns to read it from the outside. What it does have, since June 2026, is the OpenTelemetry metrics path: the default guest performance metrics go to an Azure Monitor workspace at no charge, and I enable that on every machine. What I scope deliberately is everything else, the event logs, custom counters and security events that land in Log Analytics, because that is where ingestion and retention are billed. The one exception I plan around is private link: metrics-based collection does not support it yet, so a private link estate stays on the logs path until that changes. And do not build on the dependency map or service map that older monitoring guidance leans on, because onboarding new machines to them has already closed and they are being retired; build on the current agent-and-rule model instead.

Step 3: Run a PowerShell script on a machine, from Azure

This is the capability people are really asking for when they ask how to do something on the box. Run Command executes a script on the server through the agent, with nothing to install, because it is built into the Connected Machine agent itself. Two things to know before you use it: at the time of writing it is a preview feature, and it is driven from the command line and REST, not the portal. You give it a script inline or by URI, and it runs on the machine and returns the output.

# Run an inline PowerShell script on one machine
az connectedmachine run-command create \
  --resource-group "rg-arc-servers" \
  --machine-name "SVR-APP-01" \
  --name "restart-time-service" \
  --location "eastus" \
  --script "Restart-Service W32Time; Get-Service W32Time | Format-List Status"

# Or run a script hosted in storage, as a named account
az connectedmachine run-command create \
  --resource-group "rg-arc-servers" \
  --machine-name "SVR-APP-01" \
  --name "apply-fix" \
  --location "eastus" \
  --script-uri "https://<account>.blob.core.windows.net/scripts/fix.ps1?<read-only SAS token>" \
  --run-as-user "svc-maint" \
  --run-as-password "<password from your vault>"

Expected result: the command executes and its output is returned with the run-command resource. Use --script for inline content or --script-uri for a hosted file; they are the two flags I reach for. The CLI also has a --source parameter that takes the same thing as a structured object, and the PowerShell equivalents are -SourceScript and -SourceScriptUri, so do not mix the two vocabularies in one runbook. By default the script runs on the machine as Local System on Windows or root on Linux, so treat every Run Command as code execution on the server. When I need it to run as a specific account I pass both --run-as-user and --run-as-password, and on Windows the Secondary Logon service has to be running for that to work. A hosted script needs a SAS URI with read access or a public URI; Arc Run Command does not authenticate to blobs with a managed identity yet.

The permission to run one command on a machine is, in practice, permission to run any code on it. That is the power Run Command gives, and the reason Step 5 exists.

Be clear-eyed about what this is. The single action that authorizes Run Command, the write permission carried by the Azure Connected Machine Resource Administrator role, is effectively remote arbitrary code execution as a high-privilege account on the server. The Custom Script Extension is the older, extension-based way to do the same thing. Both are enormously useful and both are exactly why the machine keeps a local veto, which is the final step.

Step 4: Open a session to the server, three ways, and know which ones need no inbound port

SSH through Arc tunnels a session to the server over the agent’s existing outbound connection, with no public IP and no inbound port opened, which is a genuinely better posture than the jump box it replaces. It rides the HybridConnectivity capability. Register the Microsoft.HybridConnectivity provider once per subscription. The default connectivity endpoint and the SSH service configuration for port 22 are created for you on the first az ssh arc connection, after a prompt, and I create them explicitly with az rest only when I am scripting a fleet and want no prompts. Then you connect from your own workstation with the Azure CLI.

# Connect over the agent tunnel as a local account
az ssh arc \
  --resource-group "rg-arc-servers" \
  --name "SVR-APP-01" \
  --local-user "svc-admin"

# Tunnel RDP over the same channel instead of an interactive shell
az ssh arc --resource-group "rg-arc-servers" --name "SVR-APP-01" --local-user "svc-admin" --rdp

Failure mode on the mechanics, before we get to identity: when a connection is refused, I check three things on the server before I touch the credential. Is sshd installed and running? Does azcmagent config list show incomingconnections.enabled as true, and if incomingconnections.ports is set, does it include 22? And does the operator hold a role that permits the connection? The endpoint itself is rarely the problem, because the CLI creates it on first use.

Arc supplies the transport. What governs the session is decided by the authentication method, and there are three separate cases here that the platform is often described as if they were one. Choose deliberately, because they do not carry the same controls or the same consequences.

CaseWhat authenticatesWhat governs it
4a. Local-account SSH or RDP tunnel, Windows or LinuxA local operating system account on the machine, reached with az ssh arc --local-user or the same command with --rdpAzure role-based access control governs who may open the tunnel, and the role I assign for that is Virtual Machine Local User Login, so operators do not need Contributor to reach a shell. The sign-in itself is a local credential, so Conditional Access does not apply to it and never will. This is the default path and the one most sheets leave unexamined
4b. Linux server with Entra SSHA Microsoft Entra identity, through the AADSSHLoginForLinux extension and a system-assigned managed identity, with the Virtual Machine Administrator Login or Virtual Machine User Login roleAzure role-based access control and Conditional Access both apply, including multifactor and device checks. One documented caveat: Conditional Access that requires device compliance or Entra hybrid join is enforced only when the Azure CLI runs on Windows or macOS, not on Linux and not in Azure Cloud Shell
4c. Windows Server 2025 Entra sign-inA Microsoft Entra identity over a direct RDP connection with mstsc to the server’s hostname, through the AADLoginForWindows extension and a system-assigned managed identity, with the same two Azure roles. This does not travel through the Arc tunnel: the client needs network reach to the server’s RDP port, and the client device must be Entra joined, hybrid joined or registered in the same tenant. Windows Server 2025 with Desktop Experience onlyAzure role-based access control applies. Conditional Access is not currently supported. Enabling this Entra joins the server, and see the warning below before you enable it anywhere

Warning, and this is the one that bites hardest: enabling Entra sign-in on a Windows Server 2025 machine makes that machine Microsoft Entra joined, and an Entra-joined machine cannot also be joined to on-premises Active Directory or to Entra Domain Services. It is mutually exclusive with domain join, not additive to it. Reversing it means uninstalling the extension to disconnect the device from Entra. So this is not a sign-in preference you toggle on a domain-joined file server to try it out; it is an identity architecture decision for machines that have already left the domain or never joined it. Treat it as belonging to the same conversation as the fleet sorting in the capstone article, not to this step’s convenience.

SettingValueWhy
Entra sign-in on Windows Server 2025Enable only on machines that are not, and will not be, Active Directory domain joinedThe extension Entra joins the machine, which excludes AD and Entra Domain Services join. Enabling it on a domain-joined server is a rollback exercise, not a test
Conditional Access expectation, case 4cAssume none, and compensate elsewhereConditional Access is not supported for Windows Server Entra sign-in through Arc. Do not promise a security review that device compliance covers this path
Conditional Access expectation, case 4bReal, with a client-platform caveatLinux Entra SSH does carry Conditional Access. Device-compliance and hybrid-join conditions hold only with the Azure CLI on Windows or macOS, so document the client platform your operators actually use
Azure roles for 4b and 4cVirtual Machine Administrator Login or Virtual Machine User LoginOwner and Contributor do not grant sign-in by design. The separation between who controls a machine and who can log into it is deliberate, and useful

Expected result: case 4a opens a shell or an RDP session with a local credential and no inbound port. Case 4b signs a named Entra user in and satisfies your Conditional Access policy on the way. Case 4c signs a named Entra user in over a direct RDP connection, which means a network path to port 3389 on the server, and satisfies no Conditional Access policy, because none applies. Of the three cases, only 4a and 4b are the no-inbound-port sessions this step is named for. Failure mode to plan for on 4b and 4c: an operator with Owner on the subscription who still cannot sign in has not hit a bug, they are missing one of the two login roles.

Step 5: Set the local blocklist, the refusal the cloud cannot override

Everything in Steps 3 and 4 is cloud-granted power to reach inside a machine, and the compensating control is that the machine keeps a local veto the cloud cannot override. On a server where that reach is unacceptable, I prefer an allowlist that names only the extensions the server needs, because a block list waves through every extension Microsoft publishes next. I also turn off machine configuration with guestconfiguration.enabled false, because a custom configuration assignment is another way to run code as SYSTEM. A list does not uninstall anything already there, so I delete any Run Command or Custom Script extension from the machine in Azure before I call the veto done. Refuse the inbound connections that SSH and Windows Admin Center use, or put the whole agent in monitor mode, which allows only the monitoring and security extensions on a list Microsoft maintains, blocks anything that can change configuration or run scripts, and turns off machine configuration.

# Preferred on a sensitive server: allow only what it needs, and turn off machine configuration
azcmagent config set extensions.allowlist "Microsoft.Azure.Monitor/AzureMonitorWindowsAgent"
azcmagent config set guestconfiguration.enabled false

# If you must use a block list instead, block every script-capable handler, both platforms
azcmagent config set extensions.blocklist "Microsoft.Cplat.Core/RunCommandHandlerWindows,Microsoft.Cplat.Core/RunCommandHandlerLinux,Microsoft.Compute/CustomScriptExtension,Microsoft.Azure.Extensions/CustomScript,Microsoft.Azure.Automation.HybridWorker/HybridWorkerForWindows,Microsoft.Azure.Automation/HybridWorkerForLinux"

# Refuse the inbound connections used by SSH and Windows Admin Center
azcmagent config set incomingconnections.enabled false

# Or switch to monitor mode: only Microsoft's monitoring and security extensions, no scripts, no machine configuration
azcmagent config set config.mode monitor

# See what this agent version supports and what is currently set
azcmagent config info
azcmagent config list

Expected result: a blocked handler cannot be installed and an inbound session is refused, regardless of what role the caller holds in Azure. Failure mode: a veto set by hand on one machine drifts the moment someone rebuilds it, so enforce these through configuration management, because a blocklist that silently lapses is worse than none.

A worked example

Two servers, two deliberately opposite postures. A payment-processing server must be observable but never remotely mutated, so you install the Azure Monitor Agent and a tightly scoped data collection rule, three performance counters and the security event log, and then you set extensions.allowlist to the Azure Monitor Agent alone, guestconfiguration.enabled false, and incomingconnections.enabled false. The result is a machine that reports fully to the cloud and refuses cloud-driven extensions, machine configuration and interactive sessions, by its own configuration. A lab server gets the mirror image: Run Command left enabled so you can push a PowerShell fix in seconds, and SSH through Arc on for quick access. Same platform, same tools, two postures chosen on purpose rather than by default, which is exactly what an operations surface should let you do.

Naming convention

Leave extensions their canonical publisher and type names so they are recognizable across the fleet. Name data collection rules for what they gather and the ring they serve, for example dcr-servers-baseline and dcr-servers-security, so a glance at the rule list reads as a monitoring plan. Document the local accounts you use for SSH so access is auditable, and keep the blocklist and monitor-mode settings in your configuration baseline rather than on individual machines, so the posture survives a rebuild.

The end-to-end test

Prove both the capability and its refusal, because on this surface the refusal is half the point. On a test machine that permits it, run a harmless Run Command such as returning the hostname and confirm you receive the output in Azure. Then run the same command against a machine where you set the blocklist and confirm it is refused. A capability that works where you allowed it and is blocked where you forbade it is the proof that the operations surface and its local veto are both real. For a fuller browser console without opening a port, Windows Admin Center in the Azure portal gives you services, events and the registry signed in with your Entra identity, and its PowerShell tab asks for a local credential because that tool does not take Entra yet. Connecting needs the Windows Admin Center Administrator Login role and Reader on the machine. It is still preview for Arc as of October 2026, so use it without building a runbook that assumes it is generally available.

Rolling it back

Everything in this sheet is reversible, which is worth knowing before you pilot it rather than after. Undo it in the order the dependencies run, outermost first, and remember that removing the Azure-side object does not always undo what it put inside the guest.

  1. Remove the extension you installed in Step 1: az connectedmachine extension delete --machine-name "SVR-APP-01" --resource-group "rg-arc-servers" --extension-name "AzureMonitorWindowsAgent". Uninstalling an extension in Azure does not necessarily uninstall the software it delivered inside the guest, so confirm on the machine if that matters.
  2. Disassociate the data collection rule from the machine, then delete the rule if nothing else uses it: az monitor data-collection rule association delete --name "<association>" --resource "<machine resource id>", then az monitor data-collection rule delete --name "dcr-servers-baseline" --resource-group "rg-arc-servers". Deleting the rule with --delete-associations true does both at once, which is convenient and also a wider blast radius than you may intend.
  3. Delete the Run Command resources you created, because they persist on the machine as objects after the script has finished: az connectedmachine run-command delete --name "restart-time-service" --machine-name "SVR-APP-01" --resource-group "rg-arc-servers".
  4. Disable the remote-access path. Remove the SSH service configuration and the connectivity endpoint on the machine if you no longer want tunneled sessions, and for cases 4b or 4c remove the Entra login extension, which is also how you disconnect a Windows Server 2025 machine from Entra join.
  5. Clear the local settings you made in Step 5, and mind the order, because it is not arbitrary. Return the agent to full mode first with azcmagent config set config.mode full, since monitor mode refuses edits to the allow list and block list while it is active. Then azcmagent config clear extensions.blocklist and azcmagent config set incomingconnections.enabled true. Run azcmagent config list afterward and actually read it, because a half-cleared veto is the kind of thing that looks fine until an extension install fails for no visible reason six weeks later.
  6. Remove the same settings from your configuration baseline, or the baseline will re-apply the veto you just cleared and you will spend an afternoon blaming the agent.

Before you scale it

  • Extension installed with matching publisher and type, and the monitoring model built to tolerate an eight-week version spread.
  • Monitoring wired: the Azure Monitor Agent plus a deliberately scoped data collection rule associated to the machine, with ingestion understood as the cost and the retiring dependency map avoided.
  • Run Command exercised from the command line with --script or --script-uri, understood as remote code execution and marked preview.
  • SSH through Arc enabled per machine via the HybridConnectivity endpoint and SSH service configuration, and the authentication case chosen on purpose: local account (no Conditional Access), Linux Entra SSH (Conditional Access applies), or Windows Server 2025 Entra sign-in (no Conditional Access, and Entra join excludes domain join).
  • Local blocklist, inbound-connection, or monitor-mode settings applied to sensitive servers and enforced through configuration management.
  • End-to-end test passed: a Run Command that works where allowed and is refused where blocked.

With the management and operations surface now covered end to end, the series turns to the reason many organizations adopt Arc in the first place, which is not management at all but money: Extended Security Updates, pay-as-you-go licensing, and the waiver matrix that decides what any of this costs. The dates there are close and the rules are specific, and that is the next article.


Azure Arc
‹ Previous: [ARC 5] The Operations Surface: Extensions, Monitoring, and Remote Access
Next: [ARC 6] ESUs and Licensing: The Plane Pays for Itself ›