diff --git a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/README.md b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/README.md index cb6ce7b66..667453a89 100644 --- a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/README.md @@ -21,7 +21,7 @@ Parameter reference: | Parameter | Required | Default | Allowed values | Description | |---|---|---|---|---| -| `ManagementGroupId` | Yes | N/A | Any valid management group ID | Scope where the policy definition is created. | +| `ManagementGroupId` | No | Tenant root group | Any valid management group ID | Scope where the policy definition is created. Defaults to the tenant root management group when not specified. | | `ExtensionType` | No | `Both` | `Windows`, `Linux`, `Both` | Targets the Arc SQL extension platform. When `Both` (default), a single policy definition and assignment covers both platforms. When a specific type is selected, the naming and scope are tailored to that platform. | | `SubscriptionId` | No | Not set | Any valid subscription ID | If provided, policy assignment scope is the subscription. | | `TargetLicenseType` | Yes | N/A | `Paid`, `PAYG` | Target `LicenseType` value to enforce. | @@ -29,48 +29,83 @@ Parameter reference: Definition and assignment creation: -1. Clone the repo. +1. Download the required files. ```powershell -git clone https://github.com/microsoft/sql-server-samples.git -cd sql-server-samples/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance +# Optional: create and enter a local working directory +mkdir sql-arc-lt-compliance +cd sql-arc-lt-compliance ``` +```powershell +$baseUrl = "https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance" + +New-Item -ItemType Directory -Path policy, scripts -Force | Out-Null + +curl -sLo policy/azurepolicy.json "$baseUrl/policy/azurepolicy.json" +curl -sLo scripts/deployment.ps1 "$baseUrl/scripts/deployment.ps1" +curl -sLo scripts/start-remediation.ps1 "$baseUrl/scripts/start-remediation.ps1" +``` + +> **Note:** On Windows PowerShell 5.1, `curl` is an alias for `Invoke-WebRequest`. Use `curl.exe` instead, or run the commands in PowerShell 7+. + 2. Login to Azure. ```powershell Connect-AzAccount ``` +3. Set your variables. Only `TargetLicenseType` is required — all others are optional. + ```powershell -# Example: target both platforms (default) -.\scripts\deployment.ps1 -ManagementGroupId "" -SubscriptionId "" -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid") +# ── Required ── +$TargetLicenseType = "PAYG" # "Paid" or "PAYG" + +# ── Optional (uncomment to override defaults) ── +# $ManagementGroupId = "" # Default: tenant root management group +# $SubscriptionId = "" # Default: policy assigned at management group scope +# $ExtensionType = "Both" # "Windows", "Linux", or "Both" (default) +# $LicenseTypesToOverwrite = @("Unspecified","Paid","PAYG","LicenseOnly") # Default: all +``` -# Example: target only Linux -.\scripts\deployment.ps1 -ManagementGroupId "" -ExtensionType "Linux" -SubscriptionId "" -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid") +4. Run the deployment. + +```powershell +# Minimal — uses defaults for management group, platform, and overwrite targets +.\scripts\deployment.ps1 -TargetLicenseType $TargetLicenseType + +# With subscription scope +.\scripts\deployment.ps1 -TargetLicenseType $TargetLicenseType -SubscriptionId $SubscriptionId + +# With all options +.\scripts\deployment.ps1 ` + -ManagementGroupId $ManagementGroupId ` + -SubscriptionId $SubscriptionId ` + -ExtensionType $ExtensionType ` + -TargetLicenseType $TargetLicenseType ` + -LicenseTypesToOverwrite $LicenseTypesToOverwrite ``` -The first example (without `-ExtensionType`) will: -* Create/update a single policy definition and assignment covering **both** Windows and Linux. -* Assign that policy at the specified subscription scope. -* Enforce LicenseType = PAYG. -* Update only resources where current `LicenseType` is `Paid`. -The second example creates a Linux-specific definition and assignment, with platform-tailored naming. +This will: +* Create/update the policy definition at the management group scope. +* Create/assign the policy (at subscription scope when `-SubscriptionId` is provided, otherwise at management group scope). +* Target the selected `ExtensionType` platform(s) — `Both` by default covers Windows and Linux. +* Enforce the selected `TargetLicenseType` on resources matching the `LicenseTypesToOverwrite` filter. -Scenario examples: +**Scenario examples:** ```powershell -# Target Paid, both Linux and Windows, but only for resources with missing LicenseType or LicenseOnly (do not target PAYG) -.\scripts\deployment.ps1 -ManagementGroupId "" -TargetLicenseType "Paid" -LicenseTypesToOverwrite @("Unspecified","LicenseOnly") +# Move all Paid licenses to PAYG, both platforms +.\scripts\deployment.ps1 -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid") -# Target PAYG, but only where current LicenseType is Paid (do not target missing or LicenseOnly) -.\scripts\deployment.ps1 -ManagementGroupId "" -ExtensionType "Linux" -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid") +# Set missing and LicenseOnly to Paid, skip resources already on PAYG +.\scripts\deployment.ps1 -TargetLicenseType "Paid" -LicenseTypesToOverwrite @("Unspecified","LicenseOnly") -# Overwrite all known existing LicenseType values (Paid, PAYG, LicenseOnly), but not missing -.\scripts\deployment.ps1 -ManagementGroupId "" -ExtensionType "Linux" -TargetLicenseType "Paid" -LicenseTypesToOverwrite @("Paid","PAYG","LicenseOnly") +# Linux only — move Paid to PAYG at a specific subscription +.\scripts\deployment.ps1 -ExtensionType "Linux" -SubscriptionId "" -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid") ``` -Note: `scripts/deployment.ps1` automatically grants required roles to the policy assignment managed identity at assignment scope, preventing common `PolicyAuthorizationFailed` errors during DeployIfNotExists deployments. +> **Note:** `deployment.ps1` automatically grants required roles to the policy assignment managed identity at assignment scope, preventing common `PolicyAuthorizationFailed` errors during DeployIfNotExists deployments. ## Start Remediation @@ -78,20 +113,44 @@ Parameter reference: | Parameter | Required | Default | Allowed values | Description | |---|---|---|---|---| -| `ManagementGroupId` | Yes | N/A | Any valid management group ID | Used to resolve the policy definition/assignment naming context. | +| `ManagementGroupId` | No | Tenant root group | Any valid management group ID | Used to resolve the policy definition/assignment naming context. Defaults to the tenant root management group when not specified. | | `ExtensionType` | No | `Both` | `Windows`, `Linux`, `Both` | Must match the platform used for the assignment. When `Both` (default), remediates the combined assignment. | | `SubscriptionId` | No | Not set | Any valid subscription ID | If provided, remediation runs at subscription scope. | | `TargetLicenseType` | Yes | N/A | `Paid`, `PAYG` | Must match the assignment target license type. | | `GrantMissingPermissions` | No | `false` | Switch (`present`/`not present`) | If set, checks and assigns missing required roles before remediation. | +1. Set your variables. `TargetLicenseType` is required and must match the value used during deployment — all others are optional. + ```powershell -# Example: remediate both platforms (default) -.\scripts\start-remediation.ps1 -ManagementGroupId "" -SubscriptionId "" -TargetLicenseType "PAYG" -GrantMissingPermissions +# ── Required ── +$TargetLicenseType = "PAYG" # Must match the deployment target + +# ── Optional (uncomment to override defaults) ── +# $ManagementGroupId = "" # Default: tenant root management group +# $SubscriptionId = "" # Default: remediation runs at management group scope +# $ExtensionType = "Both" # Must match the platform used for deployment +``` + +2. Run the remediation. -# Example: remediate only Linux -.\scripts\start-remediation.ps1 -ManagementGroupId "" -ExtensionType "Linux" -SubscriptionId "" -TargetLicenseType "PAYG" -GrantMissingPermissions +```powershell +# Minimal — uses defaults for management group and platform +.\scripts\start-remediation.ps1 -TargetLicenseType $TargetLicenseType -GrantMissingPermissions + +# With subscription scope +.\scripts\start-remediation.ps1 -TargetLicenseType $TargetLicenseType -SubscriptionId $SubscriptionId -GrantMissingPermissions + +# With all options +.\scripts\start-remediation.ps1 ` + -ManagementGroupId $ManagementGroupId ` + -ExtensionType $ExtensionType ` + -SubscriptionId $SubscriptionId ` + -TargetLicenseType $TargetLicenseType ` + -GrantMissingPermissions ``` +> **Note:** Use `-GrantMissingPermissions` to automatically check and assign any missing required roles before remediation starts. + ## Managed Identity And Roles The policy assignment is created with `-IdentityType SystemAssigned`. Azure creates a managed identity on the assignment and uses it to apply DeployIfNotExists changes during enforcement and remediation. diff --git a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/policy/azurepolicy.json b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/policy/azurepolicy.json index 5450371d0..9f5634b53 100644 --- a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/policy/azurepolicy.json +++ b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/policy/azurepolicy.json @@ -1,8 +1,8 @@ { - "displayName": "Set Arc-enabled SQL Server license type to 'License With Software Assurance'", + "displayName": "Configure Arc-enabled SQL Server license type", "policyType": "Custom", "mode": "Indexed", - "description": "This policy sets the license type for Arc-enabled SQL Server to 'License With Software Assurance'. ", + "description": "This policy configures the license type for Arc-enabled SQL Server extensions to a specified target value.", "metadata": { "category": "" }, diff --git a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/deployment.ps1 b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/deployment.ps1 index 98aab3392..459459922 100644 --- a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/deployment.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/deployment.ps1 @@ -1,5 +1,5 @@ param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$ManagementGroupId, @@ -23,6 +23,11 @@ param( [switch]$SkipManagedIdentityRoleAssignment ) +if (-not $PSBoundParameters.ContainsKey('ManagementGroupId')) { + $ManagementGroupId = (Get-AzContext).Tenant.Id + Write-Output "ManagementGroupId not specified. Using tenant root management group: $ManagementGroupId" +} + $AssignmentScope = "/providers/Microsoft.Management/managementGroups/$ManagementGroupId" if ($PSBoundParameters.ContainsKey('SubscriptionId')) { @@ -55,14 +60,9 @@ else { $PolicyDefinitionName = "activate-sql-arc-$LicenseToken-$PlatformToken" $PolicyAssignmentName = "sql-arc-$LicenseToken-$PlatformToken" -if ($TargetLicenseType -eq 'PAYG') { - $PolicyDefinitionDisplayName = "Arc-enabled SQL Server ($PlatformLabel) license type to 'Pay-as-you-go'" - $PolicyAssignmentDisplayName = "Arc-enabled SQL Server ($PlatformLabel) license type to 'Pay-as-you-go'" -} -else { - $PolicyDefinitionDisplayName = "Set Arc-enabled SQL Server ($PlatformLabel) license type to 'License With Software Assurance'" - $PolicyAssignmentDisplayName = "Set Arc-enabled SQL Server ($PlatformLabel) license type to 'License With Software Assurance'" -} +$LicenseTypeLabel = if ($TargetLicenseType -eq 'PAYG') { 'Pay-as-you-go' } else { 'License With Software Assurance' } +$PolicyDefinitionDisplayName = "Configure Arc-enabled SQL Server ($PlatformLabel) license type to '$LicenseTypeLabel'" +$PolicyAssignmentDisplayName = "Configure Arc-enabled SQL Server ($PlatformLabel) license type to '$LicenseTypeLabel'" #Create policy definition New-AzPolicyDefinition ` diff --git a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/start-remediation.ps1 b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/start-remediation.ps1 index b2f895c0b..1ea317104 100644 --- a/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/start-remediation.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/scripts/start-remediation.ps1 @@ -1,5 +1,5 @@ param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$ManagementGroupId, @@ -31,6 +31,11 @@ param( [switch]$GrantMissingPermissions ) +if (-not $PSBoundParameters.ContainsKey('ManagementGroupId')) { + $ManagementGroupId = (Get-AzContext).Tenant.Id + Write-Output "ManagementGroupId not specified. Using tenant root management group: $ManagementGroupId" +} + $AssignmentScope = "/providers/Microsoft.Management/managementGroups/$ManagementGroupId" if ($PSBoundParameters.ContainsKey('SubscriptionId')) {