diff --git a/modules/Microsoft.Compute/galleries/.test/common/deploy.test.bicep b/modules/Microsoft.Compute/galleries/.test/common/deploy.test.bicep index 9078e48221..97fe520939 100644 --- a/modules/Microsoft.Compute/galleries/.test/common/deploy.test.bicep +++ b/modules/Microsoft.Compute/galleries/.test/common/deploy.test.bicep @@ -55,5 +55,23 @@ module testDeployment '../../deploy.bicep' = { principalType: 'ServicePrincipal' } ] + applications: [ + { + name: '<>-${serviceShort}-appd-001' + } + { + name: '<>-appd-002' + supportedOSType: 'Windows' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + resourceGroupResources.outputs.managedIdentityPrincipalId + ] + principalType: 'ServicePrincipal' + } + ] + } + ] } } diff --git a/modules/Microsoft.Compute/galleries/applications/.bicep/nested_roleAssignments.bicep b/modules/Microsoft.Compute/galleries/applications/.bicep/nested_roleAssignments.bicep new file mode 100644 index 0000000000..47d04db055 --- /dev/null +++ b/modules/Microsoft.Compute/galleries/applications/.bicep/nested_roleAssignments.bicep @@ -0,0 +1,71 @@ +@sys.description('Required. The IDs of the principals to assign the role to.') +param principalIds array + +@sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') +param roleDefinitionIdOrName string + +@sys.description('Required. The resource ID of the resource to apply the role assignment to.') +param resourceId string + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container"') +param condition string = '' + +@sys.description('Optional. Version of the condition.') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. Id of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +var builtInRoleNames = { + 'Compute Gallery Sharing Admin': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b') + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Desktop Virtualization Virtual Machine Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c') + 'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293') + 'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893') + 'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e') + 'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae') + 'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44') + 'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa') + 'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168') + 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') + 'Windows Admin Center Administrator Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a6333a3e-0164-44c3-b281-7a577aff287f') +} + +resource galleryApplication 'Microsoft.Compute/galleries/applications@2022-03-03' existing = { + name: '${split(resourceId, '/')[8]}/${split(resourceId, '/')[10]}' +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: { + name: guid(galleryApplication.id, principalId, roleDefinitionIdOrName) + properties: { + description: description + roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName + principalId: principalId + principalType: !empty(principalType) ? any(principalType) : null + condition: !empty(condition) ? condition : null + conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) ? delegatedManagedIdentityResourceId : null + } + scope: galleryApplication +}] diff --git a/modules/Microsoft.Compute/galleries/applications/deploy.bicep b/modules/Microsoft.Compute/galleries/applications/deploy.bicep new file mode 100644 index 0000000000..9942ddea62 --- /dev/null +++ b/modules/Microsoft.Compute/galleries/applications/deploy.bicep @@ -0,0 +1,100 @@ +@description('Required. Name of the application definition.') +param name string + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Conditional. The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment.') +@minLength(1) +param galleryName string + +@description('Optional. The description of this gallery Application Definition resource. This property is updatable.') +param applicationDefinitionDescription string = '' + +@description('Optional. The Eula agreement for the gallery Application Definition. Has to be a valid URL.') +param eula string = '' + +@description('Optional. The privacy statement uri. Has to be a valid URL.') +param privacyStatementUri string = '' + +@description('Optional. The release note uri. Has to be a valid URL.') +param releaseNoteUri string = '' + +@description('Optional. This property allows you to specify the supported type of the OS that application is built for.') +@allowed([ + 'Windows' + 'Linux' +]) +param supportedOSType string = 'Windows' + +@description('Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z.') +param endOfLifeDate string = '' + +@description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleAssignments array = [] + +@description('Optional. Tags for all resources.') +param tags object = {} + +@description('Optional. A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application.') +param customActions object = {} + +resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource gallery 'Microsoft.Compute/galleries@2022-03-03' existing = { + name: galleryName +} + +resource application 'Microsoft.Compute/galleries/applications@2022-03-03' = { + name: name + parent: gallery + location: location + tags: tags + properties: { + customActions: !empty(customActions) ? [ customActions ] : null + description: applicationDefinitionDescription + endOfLifeDate: endOfLifeDate + eula: eula + privacyStatementUri: privacyStatementUri + releaseNoteUri: releaseNoteUri + supportedOSType: supportedOSType + } +} + +module galleryApplication_roleAssignments '.bicep/nested_roleAssignments.bicep' = [for (roleAssignment, index) in roleAssignments: { + name: '${deployment().name}-Rbac-${index}' + params: { + description: contains(roleAssignment, 'description') ? roleAssignment.description : '' + principalIds: roleAssignment.principalIds + principalType: contains(roleAssignment, 'principalType') ? roleAssignment.principalType : '' + roleDefinitionIdOrName: roleAssignment.roleDefinitionIdOrName + condition: contains(roleAssignment, 'condition') ? roleAssignment.condition : '' + delegatedManagedIdentityResourceId: contains(roleAssignment, 'delegatedManagedIdentityResourceId') ? roleAssignment.delegatedManagedIdentityResourceId : '' + resourceId: application.id + } +}] + +@description('The resource group the image was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the image.') +output resourceId string = application.id + +@description('The name of the image.') +output name string = application.name + +@description('The location the resource was deployed into.') +output location string = application.location diff --git a/modules/Microsoft.Compute/galleries/applications/readme.md b/modules/Microsoft.Compute/galleries/applications/readme.md new file mode 100644 index 0000000000..8fcc2e4951 --- /dev/null +++ b/modules/Microsoft.Compute/galleries/applications/readme.md @@ -0,0 +1,258 @@ +# Application `[Microsoft.Compute/galleries/application]` + +This module deploys an Application in a Azure Compute Gallery. + +## Navigation + +- [Resource types](#Resource-types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/galleries/applications` | [2022-03-03](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/applications) | + +## Parameters + +**Required parameters** + +| Parameter Name | Type | Description | +| :-- | :-- | :-- | +| `name` | string | Name of the application definition. | + +**Conditional parameters** + +| Parameter Name | Type | Description | +| :-- | :-- | :-- | +| `galleryName` | string | The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter Name | Type | Default Value | Allowed Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `applicationDefinitionDescription` | string | `''` | | The description of this gallery Application resource. This property is updatable. | +| `customActions` | object | `{object}` | | A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application. | +| `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). | +| `endOfLife` | string | `''` | | The end of life date of the gallery Application. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z. | +| `eula` | string | `''` | | The Eula agreement for the gallery Application. Has to be a valid URL. | +| `location` | string | `[resourceGroup().location]` | | Location for all resources. | +| `privacyStatementUri` | string | `''` | | The privacy statement uri. Has to be a valid URL. | +| `releaseNoteUri` | string | `''` | | The release note uri. Has to be a valid URL. | +| `roleAssignments` | array | `[]` | | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | +| `supportedOSType` | string | `'Windows'` | `[Linux, Windows]` | Supported OS type of the application. | +| `tags` | object | `{object}` | | Tags for all resources. | + +### Parameter Usage: `roleAssignments` + +Create a role assignment for the given resource. If you want to assign a service principal / managed identity that is created in the same deployment, make sure to also specify the `'principalType'` parameter and set it to `'ServicePrincipal'`. This will ensure the role assignment waits for the principal's propagation in Azure. + +
+ +Parameter JSON format + +```json +"roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "description": "Reader Role Assignment", + "principalIds": [ + "12345678-1234-1234-1234-123456789012", // object 1 + "78945612-1234-1234-1234-123456789012" // object 2 + ] + }, + { + "roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11", + "principalIds": [ + "12345678-1234-1234-1234-123456789012" // object 1 + ], + "principalType": "ServicePrincipal" + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + description: 'Reader Role Assignment' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + '78945612-1234-1234-1234-123456789012' // object 2 + ] + } + { + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + ] + principalType: 'ServicePrincipal' + } +] +``` + +
+

+ +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +

+ +Parameter JSON format + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +tags: { + Environment: 'Non-Prod' + Contact: 'test.user@testcompany.com' + PurchaseOrder: '1234' + CostCenter: '7890' + ServiceName: 'DeploymentValidation' + Role: 'DeploymentValidation' +} +``` + +
+

+### Parameter Usage: `customActions` + +Create a list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application. + +

+ +Parameter JSON format + +```json +"customActions": { + "value": [ + { + "description": "This is a sample custom action", + "name": "Name of the custom action 1 (Required). Must be unique within the Compute Gallery", + "parameters": [ + { + "defaultValue": "Default Value of Parameter1. Only applies to string types.", + "description": "a description value to help others understands what it means.", + "name": "The parameter name. (Required)", + "required": True, + "type": "ConfigurationDataBlob, LogOutputBlob, or String" + }, + { + "defaultValue": "Default Value of Parameter2. Only applies to string types.", + "description": "a description value to help others understands what it means.", + "name": "The parameter name. (Required)", + "required": False, + "type": "ConfigurationDataBlob, LogOutputBlob, or String" + } + ], + "script": "The script to run when executing this custom action. (Required)" + }, + { + "description": "This is another sample custom action", + "name": "Name of the custom action 2 (Required). Must be unique within the Compute Gallery", + "parameters": [ + { + "defaultValue": "Default Value of Parameter1. Only applies to string types.", + "description": "a description value to help others understands what it means.", + "name": "The parameter name. (Required)", + "required": True, + "type": "ConfigurationDataBlob, LogOutputBlob, or String" + } + ], + "script": "The script to run when executing this custom action. (Required)" + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +customActions: [ + { + description: "This is a sample custom action" + name: "Name of the custom action 1 (Required). Must be unique within the Compute Gallery" + parameters: [ + { + defaultValue: "Default Value of Parameter 1. Only applies to string types." + description: "a description value to help others understands what it means." + name: "The parameter name. (Required)" + required: True, + type: "ConfigurationDataBlob, LogOutputBlob, or String" + } + { + defaultValue: "Default Value of Parameter 2. Only applies to string types." + description: "a description value to help others understands what it means." + name: "The parameter name. (Required)" + required: True, + type: "ConfigurationDataBlob, LogOutputBlob, or String" + } + ] + script: "The script to run when executing this custom action. (Required)" + } + { + description: "This is another sample custom action" + name: "Name of the custom action 2 (Required). Must be unique within the Compute Gallery" + parameters: [ + { + defaultValue: "Default Value of Parameter. Only applies to string types." + description: "a description value to help others understands what it means." + name: "The paramter name. (Required)" + required: True, + type: "ConfigurationDataBlob, LogOutputBlob, or String" + } + ] + script: "The script to run when executing this custom action. (Required)" + } +] +``` + +
+

+ +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the image. | +| `resourceGroupName` | string | The resource group the image was deployed into. | +| `resourceId` | string | The resource ID of the image. | + +## Cross-referenced modules + +_None_ diff --git a/modules/Microsoft.Compute/galleries/applications/version.json b/modules/Microsoft.Compute/galleries/applications/version.json new file mode 100644 index 0000000000..56f8d9ca40 --- /dev/null +++ b/modules/Microsoft.Compute/galleries/applications/version.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "version": "0.4" +} diff --git a/modules/Microsoft.Compute/galleries/deploy.bicep b/modules/Microsoft.Compute/galleries/deploy.bicep index 8a47cdf126..88320348ca 100644 --- a/modules/Microsoft.Compute/galleries/deploy.bicep +++ b/modules/Microsoft.Compute/galleries/deploy.bicep @@ -1,5 +1,5 @@ @minLength(1) -@description('Required. Name of the Azure Shared Image Gallery.') +@description('Required. Name of the Azure Compute Gallery.') param name string @description('Optional. Location for all resources.') @@ -8,6 +8,9 @@ param location string = resourceGroup().location @description('Optional. Description of the Azure Shared Image Gallery.') param galleryDescription string = '' +@description('Optional. Applications to create.') +param applications array = [] + @description('Optional. Images to create.') param images array = [] @@ -42,7 +45,7 @@ resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (ena } } -resource gallery 'Microsoft.Compute/galleries@2021-10-01' = { +resource gallery 'Microsoft.Compute/galleries@2022-03-03' = { name: name location: location tags: tags @@ -74,6 +77,25 @@ module gallery_roleAssignments '.bicep/nested_roleAssignments.bicep' = [for (rol } }] +// Applications +module galleries_applications 'applications/deploy.bicep' = [for (application, index) in applications: { + name: '${uniqueString(deployment().name, location)}-Gallery-Application-${index}' + params: { + name: application.name + galleryName: gallery.name + supportedOSType: contains(application, 'supportOSType') ? application.supportedOSType : 'Windows' + applicationDefinitionDescription: contains(application, 'applicationDefinitionDescription') ? application.applicationDefinitionDescription : '' + eula: contains(application, 'eula') ? application.eula : '' + privacyStatementUri: contains(application, 'privacyStatementUri') ? application.privacyStatementUri : '' + releaseNoteUri: contains(application, 'releaseNoteUri') ? application.releaseNoteUri : '' + endOfLifeDate: contains(application, 'endOfLifeDate') ? application.endOfLifeDate : '' + roleAssignments: contains(application, 'roleAssignments') ? application.roleAssignments : [] + customActions: contains(application, 'customActions') ? application.customActions : [] + tags: contains(application, 'tags') ? application.tags : {} + enableDefaultTelemetry: enableReferencedModulesTelemetry + } +}] + // Images module galleries_images 'images/deploy.bicep' = [for (image, index) in images: { name: '${uniqueString(deployment().name, location)}-Gallery-Image-${index}' diff --git a/modules/Microsoft.Compute/galleries/readme.md b/modules/Microsoft.Compute/galleries/readme.md index 081dfc396a..7455b074f9 100644 --- a/modules/Microsoft.Compute/galleries/readme.md +++ b/modules/Microsoft.Compute/galleries/readme.md @@ -16,7 +16,8 @@ This module deploys an Azure compute gallery (formerly known as shared image gal | :-- | :-- | | `Microsoft.Authorization/locks` | [2017-04-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2017-04-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Compute/galleries` | [2021-10-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Compute/2021-10-01/galleries) | +| `Microsoft.Compute/galleries` | [2022-03-03](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries) | +| `Microsoft.Compute/galleries/applications` | [2022-03-03](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/applications) | | `Microsoft.Compute/galleries/images` | [2021-10-01](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Compute/2021-10-01/galleries/images) | ## Parameters @@ -25,12 +26,13 @@ This module deploys an Azure compute gallery (formerly known as shared image gal | Parameter Name | Type | Description | | :-- | :-- | :-- | -| `name` | string | Name of the Azure Shared Image Gallery. | +| `name` | string | Name of the Azure Compute Gallery. | **Optional parameters** | Parameter Name | Type | Default Value | Allowed Values | Description | | :-- | :-- | :-- | :-- | :-- | +| `applications` | _[applications](applications/readme.md)_ array | `[]` | | Applications to create. | | `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). | | `galleryDescription` | string | `''` | | Description of the Azure Shared Image Gallery. | | `images` | _[images](images/readme.md)_ array | `[]` | | Images to create. | @@ -173,6 +175,24 @@ module galleries './Microsoft.Compute/galleries/deploy.bicep' = { // Required parameters name: '<>cgcom001' // Non-required parameters + applications: [ + { + name: '<>-cgcom-appd-001' + } + { + name: '<>-appd-002' + roleAssignments: [ + { + principalIds: [ + '' + ] + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + supportedOSType: 'Windows' + } + ] enableDefaultTelemetry: '' lock: 'CanNotDelete' roleAssignments: [ @@ -205,6 +225,26 @@ module galleries './Microsoft.Compute/galleries/deploy.bicep' = { "value": "<>cgcom001" }, // Non-required parameters + "applications": { + "value": [ + { + "name": "<>-cgcom-appd-001" + }, + { + "name": "<>-appd-002", + "roleAssignments": [ + { + "principalIds": [ + "" + ], + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "supportedOSType": "Windows" + } + ] + }, "enableDefaultTelemetry": { "value": "" },