From c0d5651c3f458bdc51f2ba034b253ae1d19202aa Mon Sep 17 00:00:00 2001 From: rajeevj0909 <32276596+rajeevj0909@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:41:46 +0100 Subject: [PATCH] Add README + portal-paste JSON for Activate Azure Benefits for Windows Arc Machines - Add README.md documenting CLI/pipeline and Azure portal deployment paths (folder had none) - Add azurepolicy.portal.json (properties-only) so the portal 'Policy rule' box accepts a paste without the 'Could not find member name' error - Cross-link to the companion SQL Server Arc license-type policy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../README.md | 66 ++++++ .../azurepolicy.portal.json | 194 ++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/README.md create mode 100644 policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/azurepolicy.portal.json diff --git a/policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/README.md b/policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/README.md new file mode 100644 index 00000000..33d0384e --- /dev/null +++ b/policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/README.md @@ -0,0 +1,66 @@ +# Activate Azure Benefits for Windows Arc Machines + +> **Looking for SQL Server instead?** To configure the **license type for Arc-enabled SQL Server** (Paid / PAYG / LicenseOnly), use the companion sample: **[Configure Arc-enabled SQL Server license type](https://github.com/microsoft/sql-server-samples/tree/master/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance)**. This policy is for **Windows Server** machines only. + +This policy activates Azure benefits for **Windows Server** machines managed by Azure Arc (`Microsoft.HybridCompute/machines`): + +- **Windows Server 2025** with a **pay-as-you-go (PGS)** license → enables the pay-as-you-go product profile (ticks *Pay-as-you-go*). +- **2025 without PGS**, or **any pre-2025** Windows Server → enables **Software Assurance** (ticks *Software Assurance*). +- Only **licensed Windows Server** resources are evaluated; unlicensed servers are ignored. + +> **Compliance note:** enabling Software Assurance is an attestation that the machine is covered by active Software Assurance. Only assign this where that is true for your estate. + +## What's in this folder + +| File | Purpose | +|---|---| +| `azurepolicy.json` | The **complete** definition, ARM-wrapped (`name`, `type`, `properties`). Use with `az` / PowerShell / pipelines. | +| `azurepolicy.rules.json` | Just the `policyRule` block. | +| `azurepolicy.parameters.json` | Just the `parameters` block. | +| `azurepolicy.portal.json` | **Portal paste** version — the `properties` contents only, ready for the portal's *Policy rule* box. | + +## Choose your deployment path + +### Option A — Command line / pipeline + +Use the split files as-is. + +**Azure CLI:** + +```bash +az policy definition create \ + --name "activate-azure-benefits-windows-arc" \ + --display-name "Activate Azure Benefits for Windows Arc Machines" \ + --rules azurepolicy.rules.json \ + --params azurepolicy.parameters.json \ + --mode Indexed +``` + +**PowerShell:** + +```powershell +New-AzPolicyDefinition ` + -Name "activate-azure-benefits-windows-arc" ` + -DisplayName "Activate Azure Benefits for Windows Arc Machines" ` + -Policy "azurepolicy.rules.json" ` + -Parameter "azurepolicy.parameters.json" ` + -Mode Indexed +``` + +Then assign and (because the effect is `DeployIfNotExists`) create a remediation task. + +### Option B — Azure Portal (copy & paste) + +The portal's **Policy definition → Policy rule** box expects **only the contents of `properties`**. Pasting the ARM-wrapped `azurepolicy.json` fails with: +*"Could not find member 'name' on object of type 'PolicyDefinitionProperties'."* + +Steps: + +1. **Policy → Definitions → + Policy definition.** +2. Set **Definition location**, **Name**, and **Category** = `Compute`. +3. Open [`azurepolicy.portal.json`](./azurepolicy.portal.json) in this folder, copy its entire contents, clear the **Policy rule** box and paste it in. +4. **Save**, then **Assign**. Because the effect is `DeployIfNotExists`, the assignment needs a **system-assigned managed identity + location** (the portal grants the Contributor role used for remediation). Create a **remediation task** for existing machines. + +## Why three files, then? + +The split (`rules` + `parameters`) exists for automation that consumes them separately. For the **portal**, you only ever paste the single `azurepolicy.portal.json` file. diff --git a/policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/azurepolicy.portal.json b/policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/azurepolicy.portal.json new file mode 100644 index 00000000..e109da77 --- /dev/null +++ b/policyDefinitions/Compute/activate-azure-benefits-for-windows-arc-machines/azurepolicy.portal.json @@ -0,0 +1,194 @@ +{ + "displayName": "Activate Azure Benefits for Windows Arc Machines", + "description": "Activate Azure benefits for Windows ARC Machines\n\nFor 2025 server, if license type is Pay-as-you-go, then this will check Pay-as-you-go box in license menu. If 2025 and not Pay-as-you-go license or not 2025 server then check Software Assurance box. This policy only checks Windows Server resources and will NOT check unlicensed servers", + "metadata": { + "version": "1.0.0", + "category": "Compute" + }, + "mode": "Indexed", + "parameters": { + "effect": { + "type": "String", + "metadata": { + "displayName": "Effect", + "description": "DeployIfNotExists, AuditIfNotExists or Disabled the execution of the Policy" + }, + "allowedValues": [ + "DeployIfNotExists", + "AuditIfNotExists", + "Disabled" + ], + "defaultValue": "DeployIfNotExists" + } + }, + "policyRule": { + "if": { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.HybridCompute/machines" + }, + { + "field": "Microsoft.HybridCompute/machines/osType", + "equals": "windows" + }, + { + "field": "Microsoft.HybridCompute/machines/licenseProfile.licenseStatus", + "equals": "Licensed" + } + ] + }, + "then": { + "effect": "[parameters('effect')]", + "details": { + "type": "Microsoft.HybridCompute/machines", + "name": "[field('name')]", + "roleDefinitionIds": [ + "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" + ], + "existenceCondition": { + "anyOf": [ + { + "allOf": [ + { + "field": "Microsoft.HybridCompute/machines/osSku", + "contains": "2025" + }, + { + "field": "Microsoft.HybridCompute/machines/licenseProfile.licenseChannel", + "contains": "PGS" + }, + { + "anyOf": [ + { + "field": "Microsoft.HybridCompute/machines/licenseProfile.productProfile.subscriptionStatus", + "equals": "Enabled" + }, + { + "field": "Microsoft.HybridCompute/machines/licenseProfile.productProfile.productFeatures[*].subscriptionStatus", + "equals": "Enabled" + } + ] + } + ] + }, + { + "allOf": [ + { + "field": "Microsoft.HybridCompute/machines/osSku", + "contains": "2025" + }, + { + "not": { + "field": "Microsoft.HybridCompute/machines/licenseProfile.licenseChannel", + "contains": "PGS" + } + }, + { + "field": "Microsoft.HybridCompute/machines/licenseProfile.softwareAssurance.softwareAssuranceCustomer", + "equals": true + } + ] + }, + { + "allOf": [ + { + "not": { + "field": "Microsoft.HybridCompute/machines/osSku", + "contains": "2025" + } + }, + { + "field": "Microsoft.HybridCompute/machines/licenseProfile.softwareAssurance.softwareAssuranceCustomer", + "equals": true + } + ] + } + ] + }, + "deployment": { + "properties": { + "mode": "incremental", + "template": { + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmName": { + "type": "string" + }, + "location": { + "type": "string" + }, + "osSku": { + "type": "string" + }, + "licenseChannel": { + "type": "string" + }, + "status": { + "type": "string" + }, + "productType": { + "type": "string" + } + }, + "resources": [ + { + "condition": "[and(equals(parameters('status'), 'Connected'), contains(parameters('licenseChannel'), 'PGS'))]", + "name": "[concat(parameters('vmName'), '/default')]", + "type": "Microsoft.HybridCompute/machines/licenseProfiles", + "location": "[parameters('location')]", + "apiVersion": "2025-01-13", + "properties": { + "productProfile": { + "productType": "[parameters('productType')]", + "subscriptionStatus": "Enabled" + } + } + }, + { + "condition": "[and(equals(parameters('status'), 'Connected'), not(contains(parameters('licenseChannel'), 'PGS')))]", + "name": "[concat(parameters('vmName'), '/default')]", + "type": "Microsoft.HybridCompute/machines/licenseProfiles", + "location": "[parameters('location')]", + "apiVersion": "2025-01-13", + "properties": { + "softwareAssurance": { + "softwareAssuranceCustomer": true + } + } + } + ], + "outputs": { + "policy": { + "type": "string", + "value": "[concat('Enabled Software Assurance for VM', ': ', parameters('vmName'))]" + } + } + }, + "parameters": { + "vmName": { + "value": "[field('name')]" + }, + "location": { + "value": "[field('location')]" + }, + "osSku": { + "value": "[field('Microsoft.HybridCompute/machines/osSku')]" + }, + "licenseChannel": { + "value": "[field('Microsoft.HybridCompute/machines/licenseProfile.licenseChannel')]" + }, + "status": { + "value": "[field('Microsoft.HybridCompute/machines/status')]" + }, + "productType": { + "value": "[field('Microsoft.HybridCompute/machines/licenseProfile.productProfile.productType')]" + } + } + } + } + } + } + } +}