├── ClientGoldenImage ├── README.md ├── azuredeploy.json ├── azuredeploy.parameters.json └── scripts │ └── setAutoWorkplaceJoin.ps1 ├── CloudConnector ├── README.md ├── azuredeploy.json ├── azuredeploy.parameters.json ├── metadata.json └── scripts │ └── DeployCitrixCloudConnector.ps1 ├── RDSLicenseServer ├── README.md ├── azuredeploy.json ├── azuredeploy.parameters.json └── metadata.json ├── README.md ├── ServerGoldenImage ├── README.md ├── azuredeploy.json └── azuredeploy.parameters.json ├── UserProfileFileStore └── README.md └── VirtualNetwork ├── README.md ├── azuredeploy.json └── azuredeploy.parameters.json /ClientGoldenImage/README.md: -------------------------------------------------------------------------------- 1 | Deploy a Citrix Cloud Golden Image to an existing Domain 2 | 3 | This template is in prototype. If it is useful to you, that is excellent. If it does not meet your scenarios, help us make it better or submit an issue. 4 | 5 | This template is designed to provision a Golden (aka Master) Windows Client image. 6 | You still have to download and install the VDA (Virtual Delivery Agent) but this should get you started in few minutes. 7 | 8 | The virtual network and subnet need to exist in the target Azure subscription. 9 | Active Directory is required and must be defined as the DNS source for the virtual network. Windows Server Active Directory or Azure AD Directory Services can be used to meet this requirement. 10 | 11 | This defaults to using the Hybrid Use Benefit licensing. Be sure to have the proper agreements in place to support that. It is your responsibility. 12 | 13 | Be sure that you DO NOT select any resource group where you will be provisioning XenApp or XenDesktop worker / session machines. You Golden / Master images are special and should be in different Resource Groups from your worker / session machines. 14 | 15 | 16 | Azure Public 17 | 18 | 19 | Azure Government 20 | 21 | 22 | Azure China 23 | 24 | 25 | Azure Germany 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ClientGoldenImage/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "type": "string", 7 | "maxLength": 15, 8 | "metadata": { 9 | "description": "the name of the golden image" 10 | } 11 | }, 12 | "windowsOSVersion": { 13 | "type": "string", 14 | "defaultValue": "Windows-10-HUB", 15 | "allowedValues": [ 16 | "Windows-10-HUB" 17 | ], 18 | "metadata": { 19 | "description": "The Windows version for the VM. This will pick the latest maintained image of this given Windows version." 20 | } 21 | }, 22 | "adminUsername": { 23 | "type": "string", 24 | "metadata": { 25 | "description": "golden image local administrator username" 26 | } 27 | }, 28 | "adminPassword": { 29 | "type": "securestring", 30 | "metadata": { 31 | "description": "golden image local administrator password" 32 | } 33 | }, 34 | "domainDnsName": { 35 | "type": "string", 36 | "minLength": 4, 37 | "metadata": { 38 | "description": "the DNS name of the domain the machine will join" 39 | } 40 | }, 41 | "domainJoinUsername": { 42 | "type": "string", 43 | "minLength": 1, 44 | "metadata": { 45 | "description": "username that will join the machine to the domain" 46 | } 47 | }, 48 | "domainJoinPassword": { 49 | "type": "securestring", 50 | "metadata": { 51 | "description": "password of the domain join user" 52 | } 53 | }, 54 | "existingVNETName": { 55 | "type": "string", 56 | "metadata": { 57 | "description": "virtual network that the golden image machine will be attached to" 58 | } 59 | }, 60 | "existingSubnetName": { 61 | "type": "string", 62 | "metadata": { 63 | "description": "subnet that the golden image machine will get an IP address from" 64 | } 65 | }, 66 | "existingVnetResourceGroup": { 67 | "type": "string", 68 | "metadata": { 69 | "description": "Resource Group that contains the existing virtual network from above" 70 | } 71 | } 72 | }, 73 | "variables": { 74 | "vmSize": "Standard_A2_v2", 75 | "imagePublisher": "MicrosoftWindowsServer", 76 | "imageOffer": "Windows-HUB", 77 | "vnetId": "[resourceId(parameters('existingVnetResourceGroup'),'Microsoft.Network/virtualNetworks', parameters('existingVNETName'))]", 78 | "subnetId": "[concat(variables('vnetId'),'/subnets/', parameters('existingSubnetName'))]", 79 | "networkSecurityGroup": "[concat(parameters('vmName'),'-nsg')]", 80 | "publicIpAddressName": "[concat(parameters('vmName'),'-pubIp')]", 81 | "OSDiskName": "[concat(parameters('vmName'),'-osdisk')]", 82 | "nicName": "[concat(parameters('vmName'),'-nic')]", 83 | "vhdStorageType": "Standard_LRS", 84 | "vhdStorageContainerName": "vhds", 85 | "vhdStorageAccountName": "[toLower(concat(take(replace(parameters('vmName'),'-',''),11), 'storage'))]", 86 | "workplaceJoinScriptDownloadUrl": "https://raw.githubusercontent.com/citrix/CitrixCloud-ARMTemplates/master/ClientGoldenImage/scripts/setAutoWorkplaceJoin.ps1" 87 | }, 88 | "resources": [ 89 | { 90 | "name": "[parameters('vmName')]", 91 | "type": "Microsoft.Compute/virtualMachines", 92 | "apiVersion": "2016-04-30-preview", 93 | "location": "[resourceGroup().location]", 94 | "dependsOn": [ 95 | "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]", 96 | "[concat('Microsoft.Storage/storageAccounts/', variables('vhdStorageAccountName'))]" 97 | ], 98 | "properties": { 99 | "osProfile": { 100 | "computerName": "[parameters('vmName')]", 101 | "adminUsername": "[parameters('adminUsername')]", 102 | "adminPassword": "[parameters('adminPassword')]", 103 | "windowsConfiguration": { 104 | "provisionVmAgent": "true" 105 | } 106 | }, 107 | "hardwareProfile": { 108 | "vmSize": "[variables('vmSize')]" 109 | }, 110 | "storageProfile": { 111 | "imageReference": { 112 | "publisher": "[variables('imagePublisher')]", 113 | "offer": "[variables('imageOffer')]", 114 | "sku": "[parameters('windowsOSVersion')]", 115 | "version": "latest" 116 | }, 117 | "osDisk": { 118 | "createOption": "FromImage", 119 | "vhd": { 120 | "uri": "[concat(reference(resourceId('Microsoft.Storage/storageAccounts', variables('vhdStorageAccountName')), '2016-01-01').primaryEndpoints['blob'], variables('vhdStorageContainerName'), '/', variables('OSDiskName'), '.vhd')]" 121 | }, 122 | "name": "[parameters('vmName')]" 123 | }, 124 | "dataDisks": [] 125 | }, 126 | "networkProfile": { 127 | "networkInterfaces": [ 128 | { 129 | "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" 130 | } 131 | ] 132 | }, 133 | "licenseType": "Windows_Server" 134 | } 135 | }, 136 | { 137 | "name": "[variables('vhdStorageAccountName')]", 138 | "type": "Microsoft.Storage/storageAccounts", 139 | "dependsOn": [], 140 | "apiVersion": "2015-06-15", 141 | "location": "[resourceGroup().location]", 142 | "properties": { 143 | "accountType": "[variables('vhdStorageType')]" 144 | } 145 | }, 146 | { 147 | "name": "[variables('nicName')]", 148 | "type": "Microsoft.Network/networkInterfaces", 149 | "apiVersion": "2016-09-01", 150 | "location": "[resourceGroup().location]", 151 | "dependsOn": [ 152 | "[concat('Microsoft.Network/publicIpAddresses/', variables('publicIpAddressName'))]", 153 | "[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroup'))]" 154 | ], 155 | "properties": { 156 | "ipConfigurations": [ 157 | { 158 | "name": "ipconfig1", 159 | "properties": { 160 | "subnet": { 161 | "id": "[variables('subnetId')]" 162 | }, 163 | "privateIPAllocationMethod": "Dynamic", 164 | "publicIpAddress": { 165 | "id": "[resourceId('Microsoft.Network/publicIpAddresses', variables('publicIpAddressName'))]" 166 | } 167 | } 168 | } 169 | ], 170 | "networkSecurityGroup": { 171 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup'))]" 172 | } 173 | } 174 | }, 175 | { 176 | "name": "[variables('publicIpAddressName')]", 177 | "type": "Microsoft.Network/publicIpAddresses", 178 | "apiVersion": "2016-08-01", 179 | "location": "[resourceGroup().location]", 180 | "dependsOn": [], 181 | "properties": { 182 | "publicIpAllocationMethod": "Dynamic" 183 | } 184 | }, 185 | { 186 | "name": "[variables('networkSecurityGroup')]", 187 | "type": "Microsoft.Network/networkSecurityGroups", 188 | "apiVersion": "2016-09-01", 189 | "location": "[resourceGroup().location]", 190 | "dependsOn": [], 191 | "properties": { 192 | "securityRules": [ 193 | { 194 | "name": "default-allow-rdp", 195 | "properties": { 196 | "priority": 1000, 197 | "sourceAddressPrefix": "*", 198 | "protocol": "Tcp", 199 | "destinationPortRange": "3389", 200 | "access": "Allow", 201 | "direction": "Inbound", 202 | "sourcePortRange": "*", 203 | "destinationAddressPrefix": "*" 204 | } 205 | } 206 | ] 207 | } 208 | }, 209 | { 210 | "type": "Microsoft.Compute/virtualMachines/extensions", 211 | "name": "[concat(parameters('vmName'), '/customScriptExtension')]", 212 | "apiVersion": "2016-04-30-preview", 213 | "location": "[resourceGroup().location]", 214 | "properties": { 215 | "publisher": "Microsoft.Compute", 216 | "type": "CustomScriptExtension", 217 | "typeHandlerVersion": "1.8", 218 | "autoUpgradeMinorVersion": true, 219 | "settings": { 220 | "fileUris": [ 221 | "[variables('workplaceJoinScriptDownloadUrl')]" 222 | ], 223 | "commandToExecute": "powershell.exe -ExecutionPolicy RemoteSigned -File setAutoWorkplaceJoin.ps1" 224 | }, 225 | "protectedSettings": {} 226 | }, 227 | "dependsOn": [ 228 | "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]" 229 | ] 230 | }, 231 | { 232 | "apiVersion": "2016-03-30", 233 | "type": "Microsoft.Compute/virtualMachines/extensions", 234 | "name": "[concat(parameters('vmName'), '/JoinDomain')]", 235 | "location": "[resourceGroup().location]", 236 | "dependsOn": [ 237 | "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('vmName'), 'customScriptExtension')]" 238 | ], 239 | "properties": { 240 | "publisher": "Microsoft.Compute", 241 | "type": "JsonADDomainExtension", 242 | "typeHandlerVersion": "1.3", 243 | "autoUpgradeMinorVersion": true, 244 | "settings": { 245 | "Name": "[parameters('domainDnsName')]", 246 | "User": "[concat(parameters('domainDnsName'), '\\', parameters('domainJoinUsername'))]", 247 | "Restart": "true", 248 | "Options": "3" 249 | }, 250 | "protectedsettings": { 251 | "Password": "[parameters('domainJoinPassword')]" 252 | } 253 | } 254 | } 255 | ], 256 | "outputs": {} 257 | } -------------------------------------------------------------------------------- /ClientGoldenImage/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "value": "" 7 | }, 8 | "adminUsername": { 9 | "value": "" 10 | }, 11 | "adminPassword": { 12 | "value": "" 13 | }, 14 | "domainDnsName": { 15 | "value": "" 16 | }, 17 | "domainJoinUsername": { 18 | "value": "" 19 | }, 20 | "domainJoinPassword": { 21 | "value": "" 22 | }, 23 | "existingVnetResourceGroup": { 24 | "value": "" 25 | }, 26 | "existingVNETName": { 27 | "value": "" 28 | }, 29 | "existingSubnetName": { 30 | "value": "" 31 | }, 32 | "windowsOSVersion":{ 33 | "value": "" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /ClientGoldenImage/scripts/setAutoWorkplaceJoin.ps1: -------------------------------------------------------------------------------- 1 | <# This disabled autoWorkplaceJoin 2 | This setting is important to block the golden image from registering with Azure AD 3 | when the Active Directory domain is integrated with Azure AD. 4 | This needs to be coupled with the GPO to enable autoWorkplaceJoin after the VMs are provisioned 5 | to whatever worker OU exists. 6 | #> 7 | start-sleep -Seconds 10 8 | Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WorkplaceJoin -Name autoWorkplaceJoin -Value 0 9 | Start-Sleep -Seconds 2 -------------------------------------------------------------------------------- /CloudConnector/README.md: -------------------------------------------------------------------------------- 1 | Deploy a Citrix Cloud Connector to an existing Domain 2 | 3 | This template is in prototype. If it is useful to you, that is excellent. If it does not meet your scenarios, help us make it better or submit an issue. 4 | 5 | This template is designed to provision Cloud Connector instances within an availability set. 6 | Provide the necessary details from Citrix Cloud to link these instances to a specific Citrix Cloud Resource Location. 7 | 8 | Required information from Citrix Cloud is: the Citrix Cloud customer ID, Citrix Cloud API key and secret, and an existing Citrix Cloud Resource Location. 9 | The virtual network and subnet need to exist in the target Azure subscription. 10 | Active Directory is required and must be defined as the DNS source for the virtual network. Windows Server Active Directory or Azure AD Directory Services can be used to meet this requirement. 11 | 12 | Be sure that you DO NOT select any resource group where you will be provisioning XenApp or XenDesktop worker / session machines. Cloud Connectors are part of your infrastrucutre and should be in different Resource Group from your worker / session machines. 13 | 14 | 15 | Azure Public 16 | 17 | 18 | Azure Government 19 | 20 | 21 | Azure China 22 | 23 | 24 | Azure Germany 25 | 26 | 27 | 28 | 29 | 30 | Before you begin, get the necessary information from Citrix Cloud: 31 | 32 | Resource Location: the connection to your resources is defined as a Resource Location in Citrix Cloud. An existing Resource Location needs to be defined that this Connector will link to. 33 | For more details on resources locations, including what they provide and where they should be located see: http://docs.citrix.com/en-us/citrix-cloud/overview/about/what-are-resource-locations.html 34 | 35 | Secure Client Connection: A secure client connection consists of a Client API Id and Client API Secret and is required to interact with Citrix Cloud APIs. 36 | It can be created on the API Access page under Identity and Access Management in Citrix Cloud. 37 | 38 | Citrix Cloud Customer ID: This can be found on the page where you create the API ID and secret. -------------------------------------------------------------------------------- /CloudConnector/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "type": "string", 7 | "maxLength": 13, 8 | "metadata": { 9 | "description": "the name pattern that will be given to the provisionined machines" 10 | } 11 | }, 12 | "vmAdminUsername": { 13 | "type": "string", 14 | "minLength": 5, 15 | "metadata": { 16 | "description": "virtual machine local administrator username" 17 | } 18 | }, 19 | "vmAdminPassword": { 20 | "type": "securestring", 21 | "metadata": { 22 | "description": "virtual machine local administrator password" 23 | } 24 | }, 25 | "domainDnsName": { 26 | "type": "string", 27 | "minLength": 4, 28 | "metadata": { 29 | "description": "the DNS name of the domain the machine will join." 30 | } 31 | }, 32 | "domainJoinUsername": { 33 | "type": "string", 34 | "minLength": 1, 35 | "metadata": { 36 | "description": "username that will join the machine to the domain. This should only be the username and not include the name of the domain in any way." 37 | } 38 | }, 39 | "domainJoinPassword": { 40 | "type": "securestring", 41 | "metadata": { 42 | "description": "password of the domain join user" 43 | } 44 | }, 45 | "existingVNETName": { 46 | "type": "string", 47 | "metadata": { 48 | "description": "virtual network the the Cloud Connector machine will be attached to" 49 | } 50 | }, 51 | "existingSubnetName": { 52 | "type": "string", 53 | "metadata": { 54 | "description": "subnet the Cloud Connector machine will get an IP address from" 55 | } 56 | }, 57 | "existingVnetResourceGroup": { 58 | "type": "string", 59 | "metadata": { 60 | "description": "Resource Group that contains the existing virtual network from above" 61 | } 62 | }, 63 | "citrixCloudCustomerId": { 64 | "type": "string", 65 | "metadata": { 66 | "description": "Citrix Cloud Customer ID" 67 | } 68 | }, 69 | "citrixCloudAPIKey": { 70 | "type": "string", 71 | "metadata": { 72 | "description": "Citrix Cloud API Key" 73 | } 74 | }, 75 | "citrixCloudAPISecret": { 76 | "type": "string", 77 | "metadata": { 78 | "description": "Citrix Cloud API Secret" 79 | } 80 | }, 81 | "citrixCloudResourceLocation": { 82 | "type": "string", 83 | "metadata": { 84 | "description": "Citrix Cloud Resource Location Name" 85 | } 86 | } 87 | }, 88 | "variables": { 89 | "vmSize": "Standard_A2_v2", 90 | "availabilitySetName": "[concat(take(trim(replace(parameters('vmName'),' ','')),11),'-availset')]", 91 | "instanceCount": 2, 92 | "imagePublisher": "MicrosoftWindowsServer", 93 | "imageOffer": "WindowsServer-HUB", 94 | "windowsOSVersion": "2016-Datacenter-HUB", 95 | "vnetId": "[resourceId(parameters('existingVnetResourceGroup'),'Microsoft.Network/virtualNetworks', parameters('existingVNETName'))]", 96 | "subnetId": "[concat(variables('vnetId'),'/subnets/', parameters('existingSubnetName'))]", 97 | "networkSecurityGroup": "[concat(parameters('vmName'),'-nsg')]", 98 | "availabilitySetPlatformUpdateDomainCount": 5, 99 | "availabilitySetPlatformFaultDomainCount": 3, 100 | "installScriptDownloadUrl": "https://raw.githubusercontent.com/citrix/CitrixCloud-ARMTemplates/master/CloudConnector/scripts/DeployCitrixCloudConnector.ps1", 101 | "citrixResourceLocation": "[concat('\"', trim(parameters('citrixCloudResourceLocation')), '\"')]", 102 | "scriptParameters": "[concat(' -CustomerId ', trim(parameters('citrixCloudCustomerId')), ' -APIClientID ', trim(parameters('citrixCloudAPIKey')), ' -APIClientSecret ', trim(parameters('citrixCloudAPISecret')), ' -ResourceLocation ', variables('citrixResourceLocation'))]" 103 | }, 104 | "resources": [ 105 | { 106 | "name": "[concat(parameters('vmName'), copyIndex())]", 107 | "type": "Microsoft.Compute/virtualMachines", 108 | "apiVersion": "2016-04-30-preview", 109 | "location": "[resourceGroup().location]", 110 | "copy": { 111 | "name": "machineCopy", 112 | "count": "[variables('instanceCount')]" 113 | }, 114 | "dependsOn": [ 115 | "nicCopy", 116 | "[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]" 117 | ], 118 | "properties": { 119 | "osProfile": { 120 | "computerName": "[concat(parameters('vmName'), copyIndex())]", 121 | "adminUsername": "[parameters('vmAdminUsername')]", 122 | "adminPassword": "[parameters('vmAdminPassword')]", 123 | "windowsConfiguration": { 124 | "provisionVmAgent": "true" 125 | } 126 | }, 127 | "hardwareProfile": { 128 | "vmSize": "[variables('vmSize')]" 129 | }, 130 | "storageProfile": { 131 | "imageReference": { 132 | "publisher": "[variables('imagePublisher')]", 133 | "offer": "[variables('imageOffer')]", 134 | "sku": "[variables('windowsOSVersion')]", 135 | "version": "latest" 136 | }, 137 | "osDisk": { 138 | "createOption": "FromImage", 139 | "managedDisk": { 140 | "storageAccountType": "Standard_LRS" 141 | } 142 | }, 143 | "dataDisks": [] 144 | }, 145 | "networkProfile": { 146 | "networkInterfaces": [ 147 | { 148 | "id": "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('vmName'), copyIndex(), '-nic'))]" 149 | } 150 | ] 151 | }, 152 | "licenseType": "Windows_Server", 153 | "availabilitySet": { 154 | "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" 155 | } 156 | } 157 | }, 158 | { 159 | "apiVersion": "2016-09-01", 160 | "type": "Microsoft.Network/networkInterfaces", 161 | "name": "[concat(parameters('vmName'), copyIndex(), '-nic')]", 162 | "location": "[resourceGroup().location]", 163 | "copy": { 164 | "name": "nicCopy", 165 | "count": "[variables('instanceCount')]" 166 | }, 167 | "properties": { 168 | "ipConfigurations": [ 169 | { 170 | "name": "ipconfig1", 171 | "properties": { 172 | "privateIPAllocationMethod": "Dynamic", 173 | "subnet": { 174 | "id": "[variables('subnetId')]" 175 | } 176 | } 177 | } 178 | ], 179 | "networkSecurityGroup": { 180 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup'))]" 181 | } 182 | }, 183 | "dependsOn": [ 184 | "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup'))]" 185 | ] 186 | }, 187 | { 188 | "type": "Microsoft.Network/networkSecurityGroups", 189 | "name": "[variables('networkSecurityGroup')]", 190 | "apiVersion": "2016-03-30", 191 | "location": "[resourceGroup().location]", 192 | "properties": { 193 | "securityRules": [ 194 | { 195 | "name": "Out_Any_Any", 196 | "properties": { 197 | "protocol": "*", 198 | "sourcePortRange": "*", 199 | "destinationPortRange": "*", 200 | "sourceAddressPrefix": "*", 201 | "destinationAddressPrefix": "*", 202 | "access": "Allow", 203 | "priority": 100, 204 | "direction": "Outbound" 205 | } 206 | } 207 | ] 208 | }, 209 | "dependsOn": [] 210 | }, 211 | { 212 | "name": "[variables('availabilitySetName')]", 213 | "type": "Microsoft.Compute/availabilitySets", 214 | "apiVersion": "2016-04-30-preview", 215 | "location": "[resourceGroup().location]", 216 | "properties": { 217 | "platformFaultDomainCount": "[variables('availabilitySetPlatformFaultDomainCount')]", 218 | "platformUpdateDomainCount": "[variables('availabilitySetPlatformUpdateDomainCount')]", 219 | "managed": true 220 | } 221 | }, 222 | { 223 | "apiVersion": "2016-03-30", 224 | "type": "Microsoft.Compute/virtualMachines/extensions", 225 | "name": "[concat(parameters('vmName'), copyIndex(), '/JoinDomain')]", 226 | "location": "[resourceGroup().location]", 227 | "copy": { 228 | "name": "joinCopy", 229 | "count": "[variables('instanceCount')]" 230 | }, 231 | "dependsOn": [ 232 | "machineCopy" 233 | ], 234 | "properties": { 235 | "publisher": "Microsoft.Compute", 236 | "type": "JsonADDomainExtension", 237 | "typeHandlerVersion": "1.3", 238 | "autoUpgradeMinorVersion": true, 239 | "settings": { 240 | "Name": "[parameters('domainDnsName')]", 241 | "User": "[concat(parameters('domainDnsName'), '\\', parameters('domainJoinUsername'))]", 242 | "Restart": "true", 243 | "Options": "3" 244 | }, 245 | "protectedsettings": { 246 | "Password": "[parameters('domainJoinPassword')]" 247 | } 248 | } 249 | }, 250 | { 251 | "type": "Microsoft.Compute/virtualMachines/extensions", 252 | "name": "[concat(parameters('vmName'), copyIndex(), '/customScriptExtension')]", 253 | "apiVersion": "2016-04-30-preview", 254 | "location": "[resourceGroup().location]", 255 | "copy": { 256 | "name": "scriptCopy", 257 | "count": "[variables('instanceCount')]" 258 | }, 259 | "properties": { 260 | "publisher": "Microsoft.Compute", 261 | "type": "CustomScriptExtension", 262 | "typeHandlerVersion": "1.8", 263 | "autoUpgradeMinorVersion": true, 264 | "settings": { 265 | "fileUris": [ 266 | "[variables('installScriptDownloadUrl')]" 267 | ], 268 | "commandToExecute": "[concat('powershell -ExecutionPolicy RemoteSigned -File DeployCitrixCloudConnector.ps1', variables('scriptParameters'))]" 269 | }, 270 | "protectedSettings": {} 271 | }, 272 | "dependsOn": [ 273 | "machineCopy", 274 | "joinCopy" 275 | ] 276 | } 277 | ] 278 | } -------------------------------------------------------------------------------- /CloudConnector/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "value": "" 7 | }, 8 | "vmAdminUsername": { 9 | "value": "" 10 | }, 11 | "vmAdminPassword": { 12 | "value": "" 13 | }, 14 | "domainName": { 15 | "value": "" 16 | }, 17 | "domainJoinUsername": { 18 | "value": "" 19 | }, 20 | "domainJoinPassword": { 21 | "value": "" 22 | }, 23 | "vnetResourceGroupName": { 24 | "value": "" 25 | }, 26 | "existingVNETName": { 27 | "value": "" 28 | }, 29 | "existingSubnetName": { 30 | "value": "" 31 | }, 32 | "citrixCloudAPIKey": { 33 | "value": "" 34 | }, 35 | "citrixCloudAPISecret": { 36 | "value": "" 37 | }, 38 | "citrixCloudCustomerId": { 39 | "value": "" 40 | }, 41 | "citrixCloudResourceLocationName": { 42 | "value": "" 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /CloudConnector/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemDisplayName": "Deploy Citrix Cloud Connector", 3 | "description": "This template creates Citrix Cloud Connector machines, joins the machines to your existing Windows Server domain on your virtual network, and associates the machines with an existing Citrix Cloud Resource Location. Contact your Citrix Cloud administrator for the API user, key, customer Id, and resource location name.", 4 | "summary": "This template creates Citrix Cloud Connector machines in your Azure subscription and joins them to Citrix Cloud.", 5 | "githubUsername": "brianehlert", 6 | "dateUpdated": "2017-06-28" 7 | } -------------------------------------------------------------------------------- /CloudConnector/scripts/DeployCitrixCloudConnector.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads and Installs the Citrix Cloud Connecter 4 | 5 | .PARAMETER CustomerId 6 | The customer ID to install the connector for 7 | 8 | .PARAMETER APIClientID: 9 | The customer's client API ID 10 | 11 | .PARAMETER APIClientSecret 12 | The customer's client API Secret 13 | 14 | .PARAMETER ResourceLocation 15 | The name of the Citrix Cloud resource location to use 16 | 17 | .PARAMETER TrustUri 18 | The URI to the trust service 19 | 20 | .PARAMETER ConnectorDowloadPath 21 | The path to download the connector to 22 | 23 | .PARAMETER ConnectorInstallerName 24 | The name of the connector installation package 25 | #> 26 | [CmdletBinding()] 27 | param( 28 | [Parameter(Mandatory=$true)] 29 | [String] $CustomerId, 30 | 31 | [Parameter(Mandatory=$true)] 32 | [String] $APIClientID, 33 | 34 | [Parameter(Mandatory=$true)] 35 | [String] $APIClientSecret, 36 | 37 | [Parameter(Mandatory=$true)] 38 | [string] $ResourceLocation, 39 | 40 | [Parameter(Mandatory=$false)] 41 | [string] $TrustUri = "https://trust.citrixworkspacesapi.net", 42 | 43 | [Parameter(Mandatory=$false)] 44 | [string] $ConnectorDowloadPath = $pwd, 45 | 46 | [Parameter(Mandatory=$false)] 47 | [string] $ConnectorInstallerName = "cwcconnector.exe" 48 | ) 49 | 50 | function Download-Connector { 51 | [CmdletBinding()] 52 | param( 53 | [Parameter(Mandatory=$false)][string]$downloadPath = $pwd, 54 | [Parameter(Mandatory=$false)][string]$connecterName = "cwcconnector.exe", 55 | [Parameter(Mandatory=$false)][System.Uri]$downloadsBaseUri = "https://downloads.cloud.com", 56 | [Parameter(Mandatory=$true)][string]$customerId 57 | ) 58 | 59 | $downloadsUri = New-Object -TypeName System.Uri -ArgumentList $downloadsBaseUri, "$customerId/connector/$connecterName" 60 | $downloadPath = (Join-Path -Path $downloadPath -ChildPath $connecterName) 61 | try { 62 | # Invoke-WebRequest -Uri $downloadsUri -OutFile $downloadPath 63 | $webClient = New-Object System.Net.WebClient 64 | $webClient.DownloadFile($downloadsUri, $downloadPath) 65 | Unblock-File $downloadPath 66 | } 67 | catch { 68 | Throw "Unable to download connector $_" 69 | } 70 | if (Test-Path $downloadPath) { 71 | "Connector downloaded succesfully from $downloadsUri to $downloadPath" 72 | } else { 73 | Throw "Unable to download connector from $downloadsUri to $downloadPath" 74 | } 75 | } 76 | 77 | function Get-CustomerResourceLocations { 78 | [CmdletBinding()] 79 | param( 80 | [Parameter(Mandatory=$true)][string]$CustomerId, 81 | [Parameter(Mandatory=$true)][string] $ClientId, 82 | [Parameter(Mandatory=$true)][string] $ClientSecret, 83 | [Parameter(Mandatory=$true)][string] $TrustUri, 84 | [Parameter(Mandatory=$false)][System.Uri] $registryServiceBaseUri = "https://registry.citrixworkspacesapi.net", 85 | [Parameter(Mandatory=$false)][switch]$ReturnPSObject 86 | ) 87 | $ErrorActionPreference = "Stop" 88 | 89 | #GET Auth Header 90 | $registryServiceUri = New-Object -TypeName System.Uri -ArgumentList $registryServiceBaseUri, "$CustomerId/resourcelocations" 91 | $AuthHeader = New-BearerAuthHeaderFromSecureClient -ClientId $ClientId -ClientSecret $ClientSecret -TrustUri $TrustUri 92 | write-verbose $AuthHeader.Authorization 93 | 94 | #Get Customer resource location 95 | $getResponse = $null 96 | try { 97 | $getResponse = Invoke-RestMethod -Method GET -Uri $registryServiceUri -Headers $AuthHeader -ContentType "application/json" -Verbose 98 | } 99 | catch { 100 | $_.Exception.Response 101 | } 102 | 103 | if (-not $getResponse) { 104 | Write-Verbose "No response from endpoint $registryServiceUri" -Verbose 105 | } 106 | 107 | if ($ReturnPSObject) { 108 | return $getResponse 109 | } else { 110 | Write-Output (ConvertTo-Json $getResponse) 111 | } 112 | } 113 | 114 | function New-BearerAuthHeaderFromSecureClient { 115 | <# 116 | .SYNOPSIS 117 | Creates a bearer authorization header using a customer's secure client (ID & secret) 118 | 119 | .DESCRIPTION 120 | This command calls New-BearerAuthHeaderValue function to create a new bearer token. 121 | Then return the authorization header CWSAuth bearer=. 122 | 123 | .PARAMETER ClientId 124 | A client id for the customer 125 | 126 | .PARAMETER ClientSecret 127 | A corresponding client secret of the client id specified. 128 | 129 | .PARAMETER TrustUri 130 | The trust url. 131 | 132 | #> 133 | [CmdletBinding()] 134 | param( 135 | [Parameter(Mandatory=$true)] 136 | [string] $ClientId, 137 | 138 | [Parameter(Mandatory=$true)] 139 | [string] $ClientSecret, 140 | 141 | [Parameter(Mandatory=$true)] 142 | [string] $TrustUri 143 | ) 144 | $BearerAuthHeaderValue = New-BearerAuthHeaderValue -ClientId $ClientId -ClientSecret $ClientSecret -TrustUri $TrustUri 145 | return @{"Authorization" = $BearerAuthHeaderValue} 146 | } 147 | 148 | function New-BearerAuthHeaderValue { 149 | <# 150 | .SYNOPSIS 151 | Create a new bearer token using a Customer's Secure Client 152 | 153 | .DESCRIPTION 154 | This command contacts trust URI to obtain a bearer token. 155 | 156 | .PARAMETER ClientId 157 | A client id for the customer 158 | 159 | .PARAMETER ClientSecret 160 | A corresponding client secret of the client id specified. 161 | 162 | .PARAMETER TrustUri 163 | The trust url. 164 | 165 | .PARAMETER Timeout 166 | The Invoke-RestMethod timeout used when contacting the trust url. 167 | #> 168 | 169 | [CmdletBinding()] 170 | param( 171 | [Parameter(Mandatory=$true)] 172 | [string] $ClientId, 173 | 174 | [Parameter(Mandatory=$true)] 175 | [string] $ClientSecret, 176 | 177 | [Parameter(Mandatory=$true)] 178 | [string] $TrustUri, 179 | 180 | [Parameter(Mandatory=$false)] 181 | [Int] $Timeout = 300 182 | ) 183 | 184 | $endPoint = "root/tokens/clients" 185 | $trustUri = "$TrustUri/$endPoint" 186 | 187 | $Body = @{ 188 | clientId = $ClientId 189 | clientSecret = $ClientSecret 190 | } 191 | write-verbose "[Body]: $(ConvertTo-Json $Body)" 192 | 193 | try { 194 | $response = Invoke-RestMethod -Uri $trustUri -Method "Post" -Body (ConvertTo-Json $Body) -ContentType application/json -TimeoutSec $Timeout -Verbose 195 | } catch [System.Net.WebException] { 196 | Write-Verbose "Trust endpoint failed: $_" 197 | throw $_ 198 | } 199 | Write-Verbose "[Response] $(ConvertTo-Json $response)" 200 | 201 | $BearerAuthHeaderValue = "CWSAuth bearer=`"$($response.token)`"" 202 | 203 | return $BearerAuthHeaderValue 204 | } 205 | 206 | #Download Connector 207 | Download-Connector -downloadPath $ConnectorDowloadPath -connecterName $ConnectorInstallerName -customerId $CustomerId 208 | 209 | #Get Resource location id 210 | $customerResourceLocations = Get-CustomerResourceLocations -CustomerId $CustomerId -ClientId $APIClientID -ClientSecret $APIClientSecret -TrustUri $TrustUri -ReturnPSObject -verbose 211 | $SpecifiedResourceLocation = $customerResourceLocations.items | where {$_.name -eq $ResourceLocation} 212 | if ($SpecifiedResourceLocation) { 213 | "Customer ResourceLocations $($SpecifiedResourceLocation.id)" 214 | } else { 215 | Throw "Unable to find a resource location named $ResourceLocation" 216 | } 217 | 218 | #Install Connector 219 | $args = "/q /CustomerName:$CustomerId /ClientId:$APIClientID /ClientSecret:$APIClientSecret /Location:$($SpecifiedResourceLocation.id) /AcceptTermsOfService:true" 220 | $ConnectorInstaller = (join-path -Path $ConnectorDowloadPath -ChildPath $ConnectorInstallerName) 221 | "** Installing... $ConnectorInstaller with arguments $args ." 222 | Start-Process $ConnectorInstaller $args -Wait -------------------------------------------------------------------------------- /RDSLicenseServer/README.md: -------------------------------------------------------------------------------- 1 | Deploy an RDS License Server to an existing Domain 2 | 3 | This template is in prototype. If it is useful to you, that is excellent. If it does not meet your scenarios, help us make it better or submit an issue. 4 | 5 | This template is designed to provision an RDS License Server. 6 | Following creation of the RDS License Server you will need to logon as a domain user, activate the license server, and install licenses. 7 | - https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-activate-license-server 8 | - https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-install-cals 9 | 10 | The virtual network and subnet need to exist in the target Azure subscription. 11 | Active Directory is required and must be defined as the DNS source for the virtual network. Windows Server Active Directory or Azure AD Directory Services can be used to meet this requirement. 12 | 13 | Be sure that you DO NOT select any resource group where you will be provisioning XenApp or XenDesktop worker / session machines. An RDS License Server is part of your infrastructure for XenApp and should be in different Resource Group from your worker / session machines. 14 | 15 | 16 | Azure Public 17 | 18 | 19 | Azure Government 20 | 21 | 22 | Azure China 23 | 24 | 25 | Azure Germany 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /RDSLicenseServer/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "type": "string", 7 | "maxLength": 13, 8 | "metadata": { 9 | "description": "the name pattern that will be given to the provisionined machine" 10 | } 11 | }, 12 | "vmAdminUsername": { 13 | "type": "string", 14 | "minLength": 5, 15 | "metadata": { 16 | "description": "virtual machine local administrator username" 17 | } 18 | }, 19 | "vmAdminPassword": { 20 | "type": "securestring", 21 | "metadata": { 22 | "description": "virtual machine local administrator password" 23 | } 24 | }, 25 | "domainDnsName": { 26 | "type": "string", 27 | "minLength": 4, 28 | "metadata": { 29 | "description": "the DNS name of the domain the machine will join" 30 | } 31 | }, 32 | "domainJoinUsername": { 33 | "type": "string", 34 | "minLength": 1, 35 | "metadata": { 36 | "description": "username that will join the machine to the domain" 37 | } 38 | }, 39 | "domainJoinPassword": { 40 | "type": "securestring", 41 | "metadata": { 42 | "description": "password of the domain join user" 43 | } 44 | }, 45 | "existingVNETName": { 46 | "type": "string", 47 | "metadata": { 48 | "description": "virtual network the RDS License Server machine will be attached to" 49 | } 50 | }, 51 | "existingSubnetName": { 52 | "type": "string", 53 | "metadata": { 54 | "description": "subnet the RDS License Server machine will get an IP address from" 55 | } 56 | }, 57 | "existingVnetResourceGroup": { 58 | "type": "string", 59 | "metadata": { 60 | "description": "Resource Group that contains the existing virtual network from above" 61 | } 62 | } 63 | }, 64 | "variables": { 65 | "vmSize": "Standard_A1_v2", 66 | "imagePublisher": "MicrosoftWindowsServer", 67 | "imageOffer": "WindowsServer-HUB", 68 | "windowsOSVersion": "2016-Datacenter-HUB", 69 | "vnetId": "[resourceId(parameters('existingVnetResourceGroup'),'Microsoft.Network/virtualNetworks', parameters('existingVNETName'))]", 70 | "subnetId": "[concat(variables('vnetId'),'/subnets/', parameters('existingSubnetName'))]", 71 | "networkSecurityGroup": "[concat(parameters('vmName'),'-nsg')]", 72 | "publicIpAddressName": "[concat(parameters('vmName'),'-pubIp')]", 73 | "nicName": "[concat(parameters('vmName'),'-nic')]" 74 | }, 75 | "resources": [ 76 | { 77 | "name": "[parameters('vmName')]", 78 | "type": "Microsoft.Compute/virtualMachines", 79 | "apiVersion": "2016-04-30-preview" , 80 | "location": "[resourceGroup().location]", 81 | "dependsOn": [ 82 | "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" 83 | ], 84 | "properties": { 85 | "osProfile": { 86 | "computerName": "[parameters('vmName')]", 87 | "adminUsername": "[parameters('vmAdminUsername')]", 88 | "adminPassword": "[parameters('vmAdminPassword')]", 89 | "windowsConfiguration": { 90 | "provisionVmAgent": "true" 91 | } 92 | }, 93 | "hardwareProfile": { 94 | "vmSize": "[variables('vmSize')]" 95 | }, 96 | "storageProfile": { 97 | "imageReference": { 98 | "publisher": "[variables('imagePublisher')]", 99 | "offer": "[variables('imageOffer')]", 100 | "sku": "[variables('windowsOSVersion')]", 101 | "version": "latest" 102 | }, 103 | "osDisk": { 104 | "createOption": "FromImage", 105 | "managedDisk": { 106 | "storageAccountType": "Standard_LRS" 107 | } 108 | }, 109 | "dataDisks": [] 110 | }, 111 | "networkProfile": { 112 | "networkInterfaces": [ 113 | { 114 | "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" 115 | } 116 | ] 117 | }, 118 | "licenseType": "Windows_Server" 119 | } 120 | }, 121 | { 122 | "apiVersion": "2016-09-01", 123 | "type": "Microsoft.Network/networkInterfaces", 124 | "name": "[variables('nicName')]", 125 | "location": "[resourceGroup().location]", 126 | "dependsOn": [ 127 | "[concat('Microsoft.Network/publicIpAddresses/', variables('publicIpAddressName'))]", 128 | "[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroup'))]" 129 | ], 130 | "properties": { 131 | "ipConfigurations": [ 132 | { 133 | "name": "ipconfig1", 134 | "properties": { 135 | "privateIPAllocationMethod": "Dynamic", 136 | "subnet": { 137 | "id": "[variables('subnetId')]" 138 | }, 139 | "publicIpAddress": { 140 | "id": "[resourceId('Microsoft.Network/publicIpAddresses', variables('publicIpAddressName'))]" 141 | } 142 | } 143 | } 144 | ], 145 | "networkSecurityGroup": { 146 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup'))]" 147 | } 148 | } 149 | }, 150 | { 151 | "name": "[variables('publicIpAddressName')]", 152 | "type": "Microsoft.Network/publicIpAddresses", 153 | "apiVersion": "2016-08-01", 154 | "location": "[resourceGroup().location]", 155 | "dependsOn": [], 156 | "properties": { 157 | "publicIpAllocationMethod": "Dynamic" 158 | } 159 | }, 160 | { 161 | "type": "Microsoft.Network/networkSecurityGroups", 162 | "name": "[variables('networkSecurityGroup')]", 163 | "apiVersion": "2016-03-30", 164 | "location": "[resourceGroup().location]", 165 | "properties": { 166 | "securityRules": [ 167 | { 168 | "name": "default-allow-rdp", 169 | "properties": { 170 | "priority": 1000, 171 | "sourceAddressPrefix": "*", 172 | "protocol": "Tcp", 173 | "destinationPortRange": "3389", 174 | "access": "Allow", 175 | "direction": "Inbound", 176 | "sourcePortRange": "*", 177 | "destinationAddressPrefix": "*" 178 | } 179 | } 180 | ] 181 | }, 182 | "dependsOn": [] 183 | }, 184 | { 185 | "apiVersion": "2016-04-30-preview" , 186 | "type": "Microsoft.Compute/virtualMachines/extensions", 187 | "name": "[concat(parameters('vmName'), '/JoinDomain')]", 188 | "location": "[resourceGroup().location]", 189 | "dependsOn": [ 190 | "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]" 191 | ], 192 | "properties": { 193 | "publisher": "Microsoft.Compute", 194 | "type": "JsonADDomainExtension", 195 | "typeHandlerVersion": "1.3", 196 | "autoUpgradeMinorVersion": true, 197 | "settings": { 198 | "Name": "[parameters('domainDnsName')]", 199 | "User": "[concat(parameters('domainDnsName'), '\\', parameters('domainJoinUsername'))]", 200 | "Restart": "true", 201 | "Options": "3" 202 | }, 203 | "protectedsettings": { 204 | "Password": "[parameters('domainJoinPassword')]" 205 | } 206 | } 207 | }, 208 | { 209 | "type": "Microsoft.Compute/virtualMachines/extensions", 210 | "name": "[concat(parameters('vmName'), '/customScriptExtension')]", 211 | "apiVersion": "2016-04-30-preview" , 212 | "location": "[resourceGroup().location]", 213 | "properties": { 214 | "publisher": "Microsoft.Compute", 215 | "type": "CustomScriptExtension", 216 | "typeHandlerVersion": "1.8", 217 | "autoUpgradeMinorVersion": true, 218 | "settings": { 219 | "fileUris": [], 220 | "commandToExecute": "powershell.exe -ExecutionPolicy RemoteSigned -Command Add-WindowsFeature -Name RDS-Licensing -IncludeAllSubFeature -Restart" 221 | }, 222 | "protectedSettings": {} 223 | }, 224 | "dependsOn": [ 225 | "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('vmName'), 'JoinDomain')]" 226 | ] 227 | } 228 | ] 229 | } -------------------------------------------------------------------------------- /RDSLicenseServer/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "value": "" 7 | }, 8 | "vmAdminUsername": { 9 | "value": "" 10 | }, 11 | "vmAdminPassword": { 12 | "value": "" 13 | }, 14 | "domainName": { 15 | "value": "" 16 | }, 17 | "domainJoinUsername": { 18 | "value": "" 19 | }, 20 | "domainJoinPassword": { 21 | "value": "" 22 | }, 23 | "vnetResourceGroupName": { 24 | "value": "" 25 | }, 26 | "existingVNETName": { 27 | "value": "" 28 | }, 29 | "existingSubnetName": { 30 | "value": "" 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /RDSLicenseServer/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemDisplayName": "Deploy RDS License Server", 3 | "description": "This template a single RDS License Server machine, joins the machine to your existing Windows Server domain on your virtual network, You are still required to logon, activate, and allocate licenses to this license server", 4 | "summary": "This template creates an RDS License Server machine in your Azure subscription.", 5 | "githubUsername": "brianehlert", 6 | "dateUpdated": "2017-08-15" 7 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CitrixCloud-ARMTemplates 2 | Azure Resource Manager Templates to aide in onboarding to and lifecycle management in the Azure Cloud. 3 | 4 | A collection of Azure Resource Manager Templates that can be used in supporting your success on Azure. 5 | Each Template exists within a single folder and can be used programatically or using the Deploy to Azure links. 6 | 7 | These templates are designed to aide in integration with existing infrastructure for PoC or production deployments. 8 | They can be used to create and be portions of many different topologies in Azure. 9 | -------------------------------------------------------------------------------- /ServerGoldenImage/README.md: -------------------------------------------------------------------------------- 1 | Deploy a Citrix Cloud Golden Image to an existing Domain 2 | 3 | This template is in prototype. If it is useful to you, that is excellent. If it does not meet your scenarios, help us make it better or submit an issue. 4 | 5 | This template is designed to provision a Golden (aka Master) Windows Server image. 6 | You still have to download and install the VDA (Virtual Delivery Agent) but this should get you started in few minutes. 7 | 8 | The virtual network and subnet need to exist in the target Azure subscription. 9 | Active Directory is required and must be defined as the DNS source for the virtual network. Windows Server Active Directory or Azure AD Directory Services can be used to meet this requirement. 10 | 11 | This defaults to using the Hybrid Use Benefit licensing. Be sure to have the proper agreements in place to support that. It is your responsibility. 12 | 13 | Be sure that you DO NOT select any resource group where you will be provisioning XenApp or XenDesktop worker / session machines. You Golden / Master images are special and should be in different Resource Groups from your worker / session machines. 14 | 15 | 16 | Azure Public 17 | 18 | 19 | Azure Government 20 | 21 | 22 | Azure China 23 | 24 | 25 | Azure Germany 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ServerGoldenImage/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "type": "string", 7 | "maxLength": 15, 8 | "metadata": { 9 | "description": "the name of the golden image" 10 | } 11 | }, 12 | "windowsOSVersion": { 13 | "type": "string", 14 | "defaultValue": "2016-Datacenter-HUB", 15 | "allowedValues": [ 16 | "2012-R2-Datacenter-HUB", 17 | "2016-Datacenter-HUB" 18 | ], 19 | "metadata": { 20 | "description": "The Windows version for the VM. This will pick the latest maintained image of this given Windows version." 21 | } 22 | }, 23 | "adminUsername": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "golden image local administrator username" 27 | } 28 | }, 29 | "adminPassword": { 30 | "type": "securestring", 31 | "metadata": { 32 | "description": "golden image local administrator password" 33 | } 34 | }, 35 | "domainDnsName": { 36 | "type": "string", 37 | "minLength": 4, 38 | "metadata": { 39 | "description": "the DNS name of the domain the machine will join" 40 | } 41 | }, 42 | "domainJoinUsername": { 43 | "type": "string", 44 | "minLength": 1, 45 | "metadata": { 46 | "description": "username that will join the machine to the domain" 47 | } 48 | }, 49 | "domainJoinPassword": { 50 | "type": "securestring", 51 | "metadata": { 52 | "description": "password of the domain join user" 53 | } 54 | }, 55 | "existingVNETName": { 56 | "type": "string", 57 | "metadata": { 58 | "description": "virtual network that the golden image machine will be attached to" 59 | } 60 | }, 61 | "existingSubnetName": { 62 | "type": "string", 63 | "metadata": { 64 | "description": "subnet that the golden image machine will get an IP address from" 65 | } 66 | }, 67 | "existingVnetResourceGroup": { 68 | "type": "string", 69 | "metadata": { 70 | "description": "Resource Group that contains the existing virtual network referenced above" 71 | } 72 | } 73 | }, 74 | "variables": { 75 | "vmSize": "Standard_A2_v2", 76 | "imagePublisher": "MicrosoftWindowsServer", 77 | "imageOffer": "WindowsServer-HUB", 78 | "vnetId": "[resourceId(parameters('existingVnetResourceGroup'),'Microsoft.Network/virtualNetworks', parameters('existingVNETName'))]", 79 | "subnetId": "[concat(variables('vnetId'),'/subnets/', parameters('existingSubnetName'))]", 80 | "networkSecurityGroup": "[concat(parameters('vmName'),'-nsg')]", 81 | "publicIpAddressName": "[concat(parameters('vmName'),'-pubIp')]", 82 | "OSDiskName": "[concat(parameters('vmName'),'-osdisk')]", 83 | "nicName": "[concat(parameters('vmName'),'-nic')]", 84 | "vhdStorageType": "Standard_LRS", 85 | "vhdStorageContainerName": "vhds", 86 | "vhdStorageAccountName": "[toLower(concat(take(replace(parameters('vmName'),'-',''),11), 'storage'))]" 87 | }, 88 | "resources": [ 89 | { 90 | "name": "[parameters('vmName')]", 91 | "type": "Microsoft.Compute/virtualMachines", 92 | "apiVersion": "2016-04-30-preview", 93 | "location": "[resourceGroup().location]", 94 | "dependsOn": [ 95 | "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]", 96 | "[concat('Microsoft.Storage/storageAccounts/', variables('vhdStorageAccountName'))]" 97 | ], 98 | "properties": { 99 | "osProfile": { 100 | "computerName": "[parameters('vmName')]", 101 | "adminUsername": "[parameters('adminUsername')]", 102 | "adminPassword": "[parameters('adminPassword')]", 103 | "windowsConfiguration": { 104 | "provisionVmAgent": "true" 105 | } 106 | }, 107 | "hardwareProfile": { 108 | "vmSize": "[variables('vmSize')]" 109 | }, 110 | "storageProfile": { 111 | "imageReference": { 112 | "publisher": "[variables('imagePublisher')]", 113 | "offer": "[variables('imageOffer')]", 114 | "sku": "[parameters('windowsOSVersion')]", 115 | "version": "latest" 116 | }, 117 | "osDisk": { 118 | "createOption": "FromImage", 119 | "vhd": { 120 | "uri": "[concat(reference(resourceId('Microsoft.Storage/storageAccounts', variables('vhdStorageAccountName')), '2016-01-01').primaryEndpoints['blob'], variables('vhdStorageContainerName'), '/', variables('OSDiskName'), '.vhd')]" 121 | }, 122 | "name": "[parameters('vmName')]" 123 | }, 124 | "dataDisks": [] 125 | }, 126 | "networkProfile": { 127 | "networkInterfaces": [ 128 | { 129 | "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" 130 | } 131 | ] 132 | }, 133 | "licenseType": "Windows_Server" 134 | } 135 | }, 136 | { 137 | "name": "[variables('vhdStorageAccountName')]", 138 | "type": "Microsoft.Storage/storageAccounts", 139 | "dependsOn": [ 140 | ], 141 | "apiVersion": "2015-06-15", 142 | "location": "[resourceGroup().location]", 143 | "properties": { 144 | "accountType": "[variables('vhdStorageType')]" 145 | } 146 | }, 147 | { 148 | "name": "[variables('nicName')]", 149 | "type": "Microsoft.Network/networkInterfaces", 150 | "apiVersion": "2016-09-01", 151 | "location": "[resourceGroup().location]", 152 | "dependsOn": [ 153 | "[concat('Microsoft.Network/publicIpAddresses/', variables('publicIpAddressName'))]", 154 | "[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroup'))]" 155 | ], 156 | "properties": { 157 | "ipConfigurations": [ 158 | { 159 | "name": "ipconfig1", 160 | "properties": { 161 | "subnet": { 162 | "id": "[variables('subnetId')]" 163 | }, 164 | "privateIPAllocationMethod": "Dynamic", 165 | "publicIpAddress": { 166 | "id": "[resourceId('Microsoft.Network/publicIpAddresses', variables('publicIpAddressName'))]" 167 | } 168 | } 169 | } 170 | ], 171 | "networkSecurityGroup": { 172 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup'))]" 173 | } 174 | } 175 | }, 176 | { 177 | "name": "[variables('publicIpAddressName')]", 178 | "type": "Microsoft.Network/publicIpAddresses", 179 | "apiVersion": "2016-08-01", 180 | "location": "[resourceGroup().location]", 181 | "dependsOn": [ 182 | ], 183 | "properties": { 184 | "publicIpAllocationMethod": "Dynamic" 185 | } 186 | }, 187 | { 188 | "name": "[variables('networkSecurityGroup')]", 189 | "type": "Microsoft.Network/networkSecurityGroups", 190 | "apiVersion": "2016-09-01", 191 | "location": "[resourceGroup().location]", 192 | "dependsOn": [ 193 | ], 194 | "properties": { 195 | "securityRules": [ 196 | { 197 | "name": "default-allow-rdp", 198 | "properties": { 199 | "priority": 1000, 200 | "sourceAddressPrefix": "*", 201 | "protocol": "Tcp", 202 | "destinationPortRange": "3389", 203 | "access": "Allow", 204 | "direction": "Inbound", 205 | "sourcePortRange": "*", 206 | "destinationAddressPrefix": "*" 207 | } 208 | } 209 | ] 210 | } 211 | }, 212 | { 213 | "apiVersion": "2016-03-30", 214 | "type": "Microsoft.Compute/virtualMachines/extensions", 215 | "name": "[concat(parameters('vmName'), '/JoinDomain')]", 216 | "location": "[resourceGroup().location]", 217 | "dependsOn": [ 218 | "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]" 219 | ], 220 | "properties": { 221 | "publisher": "Microsoft.Compute", 222 | "type": "JsonADDomainExtension", 223 | "typeHandlerVersion": "1.3", 224 | "autoUpgradeMinorVersion": true, 225 | "settings": { 226 | "Name": "[parameters('domainDnsName')]", 227 | "User": "[concat(parameters('domainDnsName'), '\\', parameters('domainJoinUsername'))]", 228 | "Restart": "true", 229 | "Options": "3" 230 | }, 231 | "protectedsettings": { 232 | "Password": "[parameters('domainJoinPassword')]" 233 | } 234 | } 235 | } 236 | ], 237 | "outputs": {} 238 | } -------------------------------------------------------------------------------- /ServerGoldenImage/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmName": { 6 | "value": "" 7 | }, 8 | "adminUsername": { 9 | "value": "" 10 | }, 11 | "adminPassword": { 12 | "value": "" 13 | }, 14 | "domainDnsName": { 15 | "value": "" 16 | }, 17 | "domainJoinUsername": { 18 | "value": "" 19 | }, 20 | "domainJoinPassword": { 21 | "value": "" 22 | }, 23 | "existingVnetResourceGroup": { 24 | "value": "" 25 | }, 26 | "existingVNETName": { 27 | "value": "" 28 | }, 29 | "existingSubnetName": { 30 | "value": "" 31 | }, 32 | "windowsOSVersion":{ 33 | "value": "" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /UserProfileFileStore/README.md: -------------------------------------------------------------------------------- 1 | If your in Azure deployment requires a user data store location (aka; highly available file server in the sky for profiles or other user persistent information) the Microsoft Storage team has already created an ARM Template for this use case. 2 | 3 | Use this Microsoft provided Azure Quick Start template to get you started: 4 | https://github.com/Azure/azure-quickstart-templates/tree/master/301-storage-spaces-direct 5 | -------------------------------------------------------------------------------- /VirtualNetwork/README.md: -------------------------------------------------------------------------------- 1 | This template creates a Virtual Network with three subnets. 2 | 3 | This template should be used during the setup of an Azure subscription for Citrix Cloud, prior to beginning the process of creating Machine Catalogs. 4 | Use this only if you don't already have a virtual network that you want to attach your VMs to. 5 | 6 | If your AD already exists on another virtual network in the same subscrition - you can link the virtual networks with a peering. 7 | If your AD already exists on another virtual network in a different subscription - you can link the virtual networks with a gateway. 8 | (remember that peerings and gateways must be set up properly on both virtual networks) 9 | If you do not already have an AD / AAD DS in Azure, please see this document: https://support.citrix.com/article/CTX224111 10 | 11 | Do not forget to return to the deployed Virtual Network and update the DNS settings of this Virtual Network after you have completed your Active Directory / Azure Active Direcotry Domain Services setup. 12 | 13 | infrastructure subnet for Cloud Connectors and other infrastructure machines. 14 | session subnet for XenApp worker machines. 15 | desktop subnet for XenDesktop worker machines. 16 | 17 | 18 | Azure Public 19 | 20 | 21 | Azure Government 22 | 23 | 24 | Azure China 25 | 26 | 27 | Azure Germany 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /VirtualNetwork/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "citrixCloudVnetName": { 6 | "type": "string", 7 | "defaultValue": "citrix-cloud", 8 | "metadata": { 9 | "description": "Citrix Cloud virtual network name" 10 | } 11 | }, 12 | "citrixCloudVnetIpAddresses": { 13 | "type": "string", 14 | "defaultValue": "172.16.0.0/16", 15 | "metadata": { 16 | "description": "Citrix Cloud virtual network address prefix. All subnets must be segments within this IP range." 17 | } 18 | }, 19 | "infrastructureSubnetName": { 20 | "type": "string", 21 | "defaultValue": "infrastructure", 22 | "metadata": { 23 | "description": "Citrix Cloud infrastructure machine subnet name" 24 | } 25 | }, 26 | "infrastructureSubnetIpRange": { 27 | "type": "string", 28 | "defaultValue": "172.16.0.0/24", 29 | "metadata": { 30 | "description": "Citrix Cloud infrastructure machine subnet prefix" 31 | } 32 | }, 33 | "sessionWorkerSubnetName": { 34 | "type": "string", 35 | "defaultValue": "session", 36 | "metadata": { 37 | "description": "session worker machine subnet name" 38 | } 39 | }, 40 | "sessionWorkerSubnetIpRange": { 41 | "type": "string", 42 | "defaultValue": "172.16.1.0/22", 43 | "metadata": { 44 | "description": "session worker machine subnet prefix" 45 | } 46 | }, 47 | "desktopWorkerSubnetName": { 48 | "type": "string", 49 | "defaultValue": "desktop", 50 | "metadata": { 51 | "description": "Desktop worker machine subnet name" 52 | } 53 | }, 54 | "desktopWorkerSubnetIpRange": { 55 | "type": "string", 56 | "defaultValue": "172.16.5.0/20", 57 | "metadata": { 58 | "description": "Desktop worker machine subnet Prefix" 59 | } 60 | } 61 | }, 62 | "variables": { 63 | "apiVersion": "2015-06-15" 64 | }, 65 | "resources": [ 66 | { 67 | "apiVersion": "[variables('apiVersion')]", 68 | "type": "Microsoft.Network/virtualNetworks", 69 | "name": "[parameters('citrixCloudVnetName')]", 70 | "location": "[resourceGroup().location]", 71 | "properties": { 72 | "addressSpace": { 73 | "addressPrefixes": [ 74 | "[parameters('citrixCloudVnetIpAddresses')]" 75 | ] 76 | }, 77 | "subnets": [ 78 | { 79 | "name": "[parameters('infrastructureSubnetName')]", 80 | "properties": { 81 | "addressPrefix": "[parameters('infrastructureSubnetIpRange')]" 82 | } 83 | }, 84 | { 85 | "name": "[parameters('sessionWorkerSubnetName')]", 86 | "properties": { 87 | "addressPrefix": "[parameters('sessionWorkerSubnetIpRange')]" 88 | } 89 | }, 90 | { 91 | "name": "[parameters('desktopWorkerSubnetName')]", 92 | "properties": { 93 | "addressPrefix": "[parameters('desktopWorkerSubnetIpRange')]" 94 | } 95 | } 96 | ] 97 | } 98 | } 99 | ] 100 | } -------------------------------------------------------------------------------- /VirtualNetwork/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "citrixCloudVnetName": { 6 | "value": "citrix-cloud" 7 | }, 8 | "citrixCloudVnetIpAddresses": { 9 | "value": "172.16.0.0/16" 10 | }, 11 | "infrastructureSubnetName": { 12 | "value": "infrastructure" 13 | }, 14 | "infrastructureSubnetIpRange": { 15 | "value": "172.16.0.0/24" 16 | }, 17 | "sessionWorkerSubnetName": { 18 | "value": "session" 19 | }, 20 | "sessionWorkerSubnetIpRange": { 21 | "value": "172.16.1.0/22" 22 | }, 23 | "desktopWorkerSubnetName": { 24 | "value": "desktop" 25 | }, 26 | "desktopWorkerSubnetIpRange": { 27 | "value": "172.16.5.0/20" 28 | } 29 | } 30 | } --------------------------------------------------------------------------------