This commit is contained in:
Marc van Eijk 2018-04-17 19:59:38 +02:00
Родитель 8a831a49b0
Коммит f14273beb0
35 изменённых файлов: 3802 добавлений и 318 удалений

Двоичные данные
rds-deployment-existing-ad/Configuration.zip

Двоичный файл не отображается.

Просмотреть файл

@ -1,64 +1,16 @@
# Create Remote Desktop Sesson Collection deployment using existing AD.
This template will create a Remote Desktop Sesson Collection farm using the PowerShell DSC Extension. Please note this expects that AD is already setup (The Vnet and Subnet names are currently in variables so, you need to update it to use yours). it creates the following resources:
# Create Remote Desktop Sesson Collection deployment
+ One Storage Account
+ One external load balancer
+ One VM configured as RDS Connection Broker and Licensing Server role
+ One VM configured as RDS Gateway and Web access Server role
+ One (or more) VMs configured as RDSH host role. NOTE: Because HA is not supported on Azure Stack Development Kit, please use only one VM or it will fail.
+ The imageSKU is choice in parameter and rest of image configuration is defined in variables - but the scripts that configure this deployment have only been tested with windows server 2012 R2 data center image and may not work on other images.
This template deploys the following resources:
## Deploying from Portal
<ul><li>storage account;</li><li>RD Gateway/RD Web Access vm;</li><li>RD Connection Broker/RD Licensing Server vm;</li><li>a number of RD Session hosts (number defined by 'numberOfRdshInstances' parameter)</li></ul>
+ Login into Azurestack portal
+ Click "New" -> "Custom" -> "Template deployment"
+ Deploy ad-non-ha template. if you already have deployed ad-non-ha, then you can use that AD deployment by its resource group for this deployment.
+ Copy conent in azuredeploy.json, Click "Edit Tempalte" and paste content, then Click "Save"
+ Fill the parameters. Again, this uses existing AD. Please see note above.
+ Click "Create new" to create new Resource Group
+ Click "Create"
The template will use existing DC, join all vms to the domain and configure RDS roles in the deployment.
## Deploying from PowerShell
Click the button below to deploy
Download azuredeploy.json and azuredeploy.azurestack.parameters.json to local machine
Modify parameter value in azuredeploy.azurestack.parameters.json as needed
Allow cookies in IE: Open IE at c:\Program Files\Internet Explorer\iexplore.exe -> Internet Options -> Privacy -> Advanced -> Click OK -> Click OK again
Launch a PowerShell console
Change working folder to the folder containing this template
```PowerShell
# Add specific Azure Stack Environment
$AadTenantId = <Tenant Id> #GUID Specific to the AAD Tenant
Add-AzureRmEnvironment -Name 'Azure Stack' `
<EFBFBD><EFBFBD><EFBFBD> -ActiveDirectoryEndpoint ("https://login.windows.net/$AadTenantId/") `
<EFBFBD><EFBFBD><EFBFBD> -ActiveDirectoryServiceEndpointResourceId "https://azurestack.local-api/" `
<EFBFBD><EFBFBD><EFBFBD> -ResourceManagerEndpoint ("https://api.azurestack.local/") `
<EFBFBD><EFBFBD><EFBFBD> -GalleryEndpoint ("https://gallery.azurestack.local/") `
<EFBFBD><EFBFBD><EFBFBD> -GraphEndpoint "https://graph.windows.net/"
# Get Azure Stack Environment Information
$env = Get-AzureRmEnvironment 'Azure Stack'
# Authenticate to AAD with Azure Stack Environment
Add-AzureRmAccount -Environment $env -Verbose
# Get Azure Stack Environment Subscription
$SubName = <Subscription Name> # The sbuscription name is the offer name by default
Get-AzureRmSubscription -SubscriptionName $SubName | Select-AzureRmSubscription
#Resource group name. Please make sure the resource group does not exist
$resourceGroupName = "rdsResourceGroup"
$deploymentName = "RDSDeployment"
$location = "Local"
New-AzurermResourceGroup -Name $resourceGroupName -Location $location
#Start new Deployment
New-AzurermResourceGroupDeployment -Name $deploymentName -ResourceGroupName $resourceGroupName `
<EFBFBD><EFBFBD><EFBFBD> -TemplateParameterFile .\azuredeploy.parameters.json -TemplateFile .\azuredeploy.json
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Frds-deployment-existing-ad%2Fazuredeploy.json" target="_blank">
<img src="http://azuredeploy.net/deploybutton.png"/>
</a>
<a href="http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Frds-deployment-existing-ad%2Fazuredeploy.json" target="_blank">
<img src="http://armviz.io/visualizebutton.png"/>
</a>

Просмотреть файл

@ -2,6 +2,12 @@
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"dnsLabelPrefix": {
"type": "string",
"metadata": {
"description": "Unique public DNS prefix for the deployment. The fqdn will look something like '<dnsname>.westus.cloudapp.azure.com'. Up to 62 chars, digits or dashes, lowercase, should start with a letter: must conform to '^[a-z][a-z0-9-]{1,61}[a-z0-9]$'. For example johndns1 will result the final RDWEB access url like https://johndns1.westus.cloudapp.azure.com/RDWeb"
}
},
"adDomainName": {
"type": "string",
"metadata": {
@ -10,14 +16,14 @@
"defaultValue": "contoso.com"
},
"adVnetName": {
"type": "string",
"type": "string",
"metadata": {
"description": "The vnet name of AD domain. For example johnvnet1"
},
"defaultValue": "[concat('ADVNET',resourceGroup().name)]"
},
"defaultValue": "[concat('ADVNET',resourceGroup().name)]"
},
"adSubnetName": {
"type": "string",
"type": "string",
"metadata": {
"description": "The subnet name of AD domain. For example johnsubnet1"
},
@ -41,261 +47,327 @@
"type": "string",
"allowedValues": [
"2012-R2-Datacenter",
"Windows-Server-Technical-Preview"
"2016-Datacenter"
],
"metadata": {
"description": "Windows server SKU"
},
"defaultValue": "2012-R2-Datacenter"
"defaultValue": "2016-Datacenter"
},
"NumberOfRemoteDesktopSessionHosts": {
"numberOfRdshInstances": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Number of RemoteDesktopSessionHosts"
}
},
"rdshVmSize": {
"type": "string",
"allowedValues": [
"Standard_A0",
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D5"
],
"metadata": {
"description": "The size of the RDSH VMs"
},
"defaultValue": "Standard_A4"
}
},
"variables": {
"dnsLabelPrefix": "[concat('rdsdns', resourceGroup().name)]",
"gwdnsLabelPrefix": "[concat('gw', resourceGroup().name)]",
"cbdnsLabelPrefix": "[concat('cb', resourceGroup().name)]",
"rdshVmSize": "Standard_A2",
"storageAccountName": "[concat('sa', resourceGroup().name)]",
"storageAccountType": "Standard_LRS",
"uniqueStorageAccountContainerName": "[concat('sc', resourceGroup().name)]",
"imagePublisher": "MicrosoftWindowsServer",
"imageOffer": "WindowsServer",
"dnsServerPrivateIp": "10.0.0.4",
"subnet-id": "[concat(resourceId('Microsoft.Network/virtualNetworks',parameters('adVnetName')),'/subnets/',parameters('adSubnetName'))]",
"publicIpRef": "publicIp",
"brokerIpRef": "brokerpublicIp",
"gatewayIpRef": "gatewaypublicIp",
"assetLocation": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-deployment-existing-ad/"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIpRef')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[variables('dnsLabelPrefix')]"
}
"variables": {
"gwdnsLabelPrefix": "[toLower(concat('gwd', resourceGroup().name))]",
"cbdnsLabelPrefix": "[toLower(concat('cbd', resourceGroup().name))]",
"storageAccountName": "[tolower(concat('rdsa', uniqueString(resourceGroup().id)))]",
"storageAccountType": "Standard_LRS",
"uniqueStorageAccountContainerName": "[toLower(concat('sac', resourceGroup().name))]",
"imagePublisher": "MicrosoftWindowsServer",
"imageOffer": "WindowsServer",
"dnsServerPrivateIp": "10.0.0.4",
"subnet-id": "[concat(resourceId('Microsoft.Network/virtualNetworks',parameters('adVnetName')),'/subnets/',parameters('adSubnetName'))]",
"publicIpRef": "publicIp",
"brokerIpRef": "brokerpublicIp",
"gatewayIpRef": "gatewaypublicIp",
"assetLocation": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-deployment/"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIpRef')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('gatewayIpRef')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[variables('gwdnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('brokerIpRef')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[variables('cbdnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"location": "[resourceGroup().location]",
"properties": {
"accountType": "[variables('storageAccountType')]"
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "gw-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "cb-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "rdsh-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/loadBalancers",
"name": "loadBalancer",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/',variables('publicIpRef'))]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "LBFE",
"properties": {
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIpRef'))]"
}
}
}
],
"backendAddressPools": [
{
"name": "LBBAP"
}
],
"loadBalancingRules": [
{
"name": "LBRule01",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadbalancer'),'/frontendIPConfigurations/LBFE')]"
},
"backendAddressPool": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadbalancer'),'/backendAddressPools/LBBAP')]"
},
"protocol": "Tcp",
"frontendPort": 443,
"backendPort": 443,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"loadDistribution": "SourceIPProtocol",
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadbalancer'),'/probes/tcpProbe')]"
}
}
},
{
"name": "LBRule02",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadbalancer'),'/frontendIPConfigurations/LBFE')]"
},
"backendAddressPool": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadbalancer'),'/backendAddressPools/LBBAP')]"
},
"protocol": "Udp",
"frontendPort": 3391,
"backendPort": 3391,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"loadDistribution": "SourceIPProtocol",
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadbalancer'),'/probes/tcpProbe')]"
}
}
}
],
"probes": [
{
"name": "tcpProbe",
"properties": {
"protocol": "Tcp",
"port": 443,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "tcpProbe01",
"properties": {
"protocol": "Tcp",
"port": 3391,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
],
"inboundNatRules": [
{
"name": "rdp",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/frontendIPConfigurations/LBFE')]"
},
"protocol": "tcp",
"frontendPort": 3389,
"backendPort": 3389,
"enableFloatingIP": false
}
}
]
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "gw-nic",
"location": "[resourceGroup().location]",
"dependsOn": [
"Microsoft.Network/loadBalancers/loadBalancer"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('gatewayIpRef'))]"
},
"subnet": {
"id": "[variables('subnet-id')]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/backendAddressPools/LBBAP')]"
}
],
"loadBalancerInboundNatRules": [
{
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/inboundNatRules/rdp')]"
}
]
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "cb-nic",
"location": "[resourceGroup().location]",
"dependsOn": [
"Microsoft.Network/loadBalancers/loadBalancer"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('brokerIpRef'))]"
},
"subnet": {
"id": "[variables('subnet-id')]"
}
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat('rdsh-', copyindex(), '-nic')]",
"location": "[resourceGroup().location]",
"copy": {
"name": "rdsh-nic-loop",
"count": "[parameters('numberOfRdshInstances')]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('gatewayIpRef')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"Microsoft.Network/loadBalancers/loadBalancer"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[variables('gwdnsLabelPrefix')]"
}
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnet-id')]"
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('brokerIpRef')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[variables('cbdnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"location": "[resourceGroup().location]",
"properties": {
"accountType": "[variables('storageAccountType')]"
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "gw-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "cb-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "rdsh-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/loadBalancers",
"name": "loadBalancer",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/',variables('publicIpRef'))]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "LBFE",
"properties": {
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIpRef'))]"
}
}
}
],
"backendAddressPools": [
{
"name": "LBBAP"
}
],
"inboundNatRules": [
{
"name": "https",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/frontendIPConfigurations/LBFE')]"
},
"protocol": "tcp",
"frontendPort": 443,
"backendPort": 443,
"enableFloatingIP": false
}
},
{
"name": "gateway",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/frontendIPConfigurations/LBFE')]"
},
"protocol": "udp",
"frontendPort": 3391,
"backendPort": 3391,
"enableFloatingIP": false
}
}
]
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "gw-nic",
"location": "[resourceGroup().location]",
"dependsOn": [
"Microsoft.Network/loadBalancers/loadBalancer",
"[concat('Microsoft.Network/publicIPAddresses/',variables('gatewayIpRef'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('gatewayIpRef'))]"
},
"subnet": {
"id": "[variables('subnet-id')]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/backendAddressPools/LBBAP')]"
}
],
"loadBalancerInboundNatRules": [
{
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/inboundNatRules/https')]"
},
{
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/inboundNatRules/gateway')]"
}
]
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "cb-nic",
"location": "[resourceGroup().location]",
"dependsOn": [
"Microsoft.Network/loadBalancers/loadBalancer",
"[concat('Microsoft.Network/publicIPAddresses/',variables('brokerIpRef'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('brokerIpRef'))]"
},
"subnet": {
"id": "[variables('subnet-id')]"
}
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat('rdsh-', copyindex(), '-nic')]",
"location": "[resourceGroup().location]",
"copy": {
"name": "rdsh-nic-loop",
"count": "[parameters('NumberOfRemoteDesktopSessionHosts')]"
},
"dependsOn": [
"Microsoft.Network/loadBalancers/loadBalancer"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnet-id')]"
}
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines",
"name": "gw-vm",
@ -327,7 +399,7 @@
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','gw-vm-os-disk.vhd')]"
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),'2016-01-01').primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','gw-vm-os-disk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
@ -382,7 +454,7 @@
"location": "[resourceGroup().location]",
"copy": {
"name": "rdsh-vm-loop",
"count": "[parameters('NumberOfRemoteDesktopSessionHosts')]"
"count": "[parameters('numberOfRdshInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
@ -391,7 +463,7 @@
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('rdshVmSize')]"
"vmSize": "[parameters('rdshVmSize')]"
},
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', 'rdsh-availabilityset')]"
@ -411,7 +483,7 @@
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','rdsh-',copyindex(),'-os-disk.vhd')]"
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),'2016-01-01').primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','rdsh-',copyindex(),'-os-disk.vhd')]"
},
"caching": "ReadWrite",
@ -493,7 +565,7 @@
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','cb-vm-os-disk.vhd')]"
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),'2016-01-01').primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','cb-vm-os-disk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
@ -521,11 +593,11 @@
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.11",
"typeHandlerVersion": "2.75",
"autoUpgradeMinorVersion": true,
"settings": {
"ModulesUrl": "[concat(variables('assetLocation'),'/Configuration.zip')]",
"ConfigurationFunction": "Configuration.ps1\\RDSDeployment",
"modulesUrl": "[concat(variables('assetLocation'),'/Configuration.zip')]",
"configurationFunction": "Configuration.ps1\\RDSDeployment",
"Properties": {
"adminCreds": {
"UserName": "[parameters('adminUsername')]",
@ -533,8 +605,8 @@
},
"connectionBroker": "[concat('broker.',parameters('adDomainName'))]",
"domainName": "[parameters('adDomainName')]",
"externalfqdn": "[concat('gateway.',parameters('adDomainName'))]",
"numberOfRdshInstances": "[parameters('NumberOfRemoteDesktopSessionHosts')]",
"externalfqdn": "[reference(variables('gatewayIpRef')).dnsSettings.fqdn]",
"numberOfRdshInstances": "[parameters('numberOfRdshInstances')]",
"sessionHostNamingPrefix": "rdsh-",
"webAccessServer": "[concat('gateway.',parameters('adDomainName'))]"
}
@ -546,5 +618,5 @@
}
}
}
]
]
}

Просмотреть файл

@ -2,5 +2,11 @@
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"dnsLabelPrefix": {
"value": "GEN-UNIQUE"
},
"adminPassword": {
"value": "GEN-PASSWORD"
}
}
}

Просмотреть файл

@ -1,7 +1,7 @@
{
"itemDisplayName": "RDS deployment using existing active directory",
"description": "This template creates a simple RDSH deployment using existing active directory in same resource group",
"summary": "Creates RDSH deployment using existing active directory in same resource group",
"githubUsername": "azurestack",
"dateUpdated": "2016-09-20"
"itemDisplayName": "RDS farm deployment using existing active directory",
"description": "This template creates a RDS farm deployment using existing active directory in same resource group",
"summary": "Creates and deploys fully functional RDS farm deployment using existing active directory in same resource group",
"githubUsername": "MahendraAgrawal",
"dateUpdated": "2016-10-12"
}

Двоичные данные
rds-deployment-ha-broker/DSC/Configuration.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,43 @@
# Provide High Availability to RD Connection Broker servers in RDS deployment
This template deploys the following resources:
* a second RD Connection Broker VM including a NIC and StorageAccount
The template will
* Create a new VM and join the new VM to the domain
* Prepare the existing RDS Deployment for RDCB HA
* Add the RD Connection Broker role to the new VM and join it to the deployment
### Prerequisites
Current Template is an extension to the Basic RDS Deployment Template, and it is mandatory to deploy any one of the template as prerequisite:
* Basic RDS deployment template
https://github.com/Azure/azure-quickstart-templates/tree/master/rds-deployment
* RDS deployment on pre-existing VNET and AD
https://github.com/Azure/azure-quickstart-templates/tree/master/rds-deployment-existing-ad
* An Azure SQL Database, or a VM running SQL Server also needs to be in place to house the RDCB Database
This template expects the same names of resources from RDS deployment, if resource names are changed in your deployment then please edit the parameters and resources accordingly, example of such resources are below:
<ul>
<li>storageAccountName: Resource must be exact same to existing RDS deployment.</li>
<li>publicIpRef: Resource must be exact same to existing RDS deployment.</li>
<li>availabilitySets: Resource must be exact same to existing RDS deployment.</li>
<li>Load-balancer: Load balancer name, Backend pool, LB-rules, Nat-Rule and NIC.</li>
<li>VMs – VM name classification which is using copy index function.</li>
<li>NIC – NIC naming convention.</li>
</ul>
Click the button below to deploy
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FRDS-Templates%2Fmaster%2Frds-deployment-ha-broker%2Fazuredeploy.json" target="_blank">
<img src="http://azuredeploy.net/deploybutton.png"/>
</a>
<a href="http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FRDS-templates%2Fmaster%2Frds-deployment-ha-broker%2Fazuredeploy.json" target="_blank">
<img src="http://armviz.io/visualizebutton.png"/>
</a>

Просмотреть файл

@ -0,0 +1,374 @@
<#
.SYNOPSIS
HA Broker configuration.
.DESCRIPTION
Script should run on the new RD Connection Broker in the deployment.
.PARAMETER newBroker
Name of the new server to add as secondary broker.
#>
param
(
[String]$existingBroker,
[String]$primaryDbConnectionString,
[string]$domainName,
[String]$username,
[String]$password,
[string]$clientAccessName,
[string]$sqlClientUrl,
[string]$dnsServer,
[string]$sqlServer
)
$localhost = [System.Net.Dns]::GetHostByName((hostname)).HostName
$domainNetbios = (Get-ADDomain -Current LocalComputer).NetBIOSName
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList @($domainNetbios + "\" + $username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
$ConfigData = @{
AllNodes = @(
@{
NodeName = 'localhost'
PSDscAllowPlainTextPassword = $true
}
)
} # End of Config Data
$Logfile = ".\CB_PostConfig1.1_{0}.log" -f (get-date -Format "yyyyMMddhhmmss")
function GetServersByRole($roleName)
{
$RemoteSqlOdbcconn = new-object System.Data.Odbc.OdbcConnection
$RemoteSqlOdbcconn.ConnectionString = $primaryDbConnectionString
$RemoteSqlOdbcconn.Open()
$OdbcCmdStr = "SELECT s.Name FROM rds.Server s INNER JOIN rds." + $roleName + " cb ON s.Id = cb.ServerId"
$RemoteSqlOdbccmd = new-object System.Data.Odbc.OdbcCommand
$RemoteSqlOdbccmd.CommandText = $OdbcCmdStr
$RemoteSqlOdbccmd.Connection = $RemoteSqlOdbcconn
$SqlRdr = $RemoteSqlOdbccmd.ExecuteReader()
while ($SqlRdr.Read() -eq $true)
{
$ServerArr += @($SqlRdr.GetString(0).Split('.')[0])
}
$SqlRdr.Close()
$RemoteSqlOdbccmd.Dispose()
$RemoteSqlOdbcconn.Close()
return $ServerArr
}
function GetIpAddress([string]$compName, [int]$ipType)
{
$IPconfigset = Get-WmiObject -ComputerName $compName Win32_NetworkAdapterConfiguration
foreach ($IPConfig in $IPconfigset)
{
if (!$Ipconfig.IPaddress -or
($Ipconfig.IPEnabled -eq $FALSE))
{
continue;
}
foreach ($addrStr in $Ipconfig.Ipaddress)
{
$addr = [System.Net.IPAddress]::Parse($addrStr);
if (($ipType -eq 4) -and
($addr.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork))
{
return $addr;
}
elseif (($ipType -eq 6) -and
($addr.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetworkV6) -and
(!$addrStr.StartsWith("fe80")))
{
return $addr;
}
}
}
}
function AddDomainComputersToRDSMgmtServerGroup()
{
$rdmsGroupName = "RDS Management Servers";
$objOU = [ADSI]("WinNT://" + $env:computername)
$objGroup = $objOU.psbase.children.find($rdmsGroupName)
$machineAcc = "Domain Computers"
$membershipExists = $objGroup.psbase.invoke("Members") | %{$_.GetType().InvokeMember("Name",'GetProperty',$null,$_,$null)} | where {$_ -eq $machineAcc}
if ( !($membershipExists.length -gt 1) )
{
$objGroup.Add("WinNT://" + $domainName + "/" + $machineAcc)
}
}
function SetupVMHA($compName)
{
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $compName);
$regKey = $reg.OpenSubKey('SYSTEM\CurrentControlSet\Services\VMHostAgent\Parameters', 'ReadWriteSubTree', 'SetValue');
$regKey.SetValue('tssdis',$brokerMachineList, 'string');
AddDomainComputersToRDSMgmtServerGroup;
}
function SetupRDSH($compName)
{
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $compName);
$regKey = $reg.OpenSubKey('SYSTEM\CurrentControlSet\Control\Terminal Server\ClusterSettings', 'ReadWriteSubTree', 'SetValue');
$regKey.SetValue('SessionDirectoryLocation',$brokerMachineList, 'string');
AddDomainComputersToRDSMgmtServerGroup;
}
function SetupRDWA($compName)
{
$rdweb = Get-WmiObject -ComputerName $compName AppSettingssection -namespace root\webadministration -Authentication 6
$appSection = $rdweb[0]
$objAppSettings = $appSection.AppSettings
foreach ($cfg in $objAppSettings)
{
if ($cfg.key.CompareTo("radcmserver") -eq 0)
{
Write-Host "Changing" $cfg.Value "to" $brokerMachineList
$cfg.Value = $brokerMachineList
}
}
$appSection.SetPropertyValue("AppSettings", $objAppSettings)
$PutOptions = New-Object System.Management.PutOptions
$PutOptions.Type = 1 # update only
$appSection.Put($PutOptions)
Write-Host "Successfully configured RDWeb's Broker name"
}
function SetupGroups($sqlServer, $computerName, $domain)
{
$computerName = $computerName.ToLower() -replace "." + $domain.ToLower()
Invoke-Command -ComputerName $sqlServer -ScriptBlock {
param( $computerName )
$grMembers = net localgroup "RDS Management Servers"
$fnd = $false
foreach ($gr in $grMembers)
{
if ( $gr -Like "*$computerName$" ) { $fnd = $true; break }
}
if ( $fnd -eq $false )
{
Write-Output ("Adding $($computerName) to the local RDS Management Servers group")
net localgroup "RDS Management Servers" /add "$computerName`$"
}
else
{
Write-Output("Computer $($computerName) is already a member of the group")
}
} -ArgumentList $computerName
}
function SetupCB($compName, $clientURL)
{
Write-Output("Starting Install of client on broker machine: $compName [end]")
Write-Output("Active broker: $activeBroker")
Write-Output("Client URL: $clientURL")
try
{
Invoke-Command -ComputerName $compName -ScriptBlock { param($clientURL, $installPath, $domainNetbios)
Write-Output("Running Invoke Command")
$installPath = "$env:temp\Install-$(Get-Date -format 'yyyy-dd hh-mm-ss').msi"
if(!(Split-Path -parent $installPath) -or !(Test-Path -PathType Container (Split-Path -parent $installPath))) {
$installPath = Join-Path $pwd (Split-Path -leaf $path)
}
Write-Output("Downloading new client from: $($installPath)")
Invoke-WebRequest -Uri $clientURL -OutFile $installPath -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer
Write-Output("FinishedDownloading Client and starting install")
sleep -Seconds 10
$result = (Start-Process -FilePath "msiexec.exe" -ArgumentList "/i ""$installPath"" /passive ADDLOCAL=ALL APPGUID={0CC618CE-F36A-415E-84B4-FB1BFF6967E1} IACCEPTSQLNCLILICENSETERMS=YES" -Wait -PassThru).ExitCode
Write-Output("Result from installing client: $($result)")
#
# Add Domain Computers to RDS Endpoint Servers group
Write-Output("Checking Domain computer registration")
$rdsServersGroupName = "RDS Endpoint Servers"
$objOU = [ADSI]("WinNT://" + $env:computername)
$objGroup = $objOU.psbase.children.find($rdsServersGroupName)
$machineAcc = "Domain Computers"
Write-Output("Checking Membership")
$membershipExists = $objGroup.psbase.invoke("Members") | %{$_.GetType().InvokeMember("Name",'GetProperty',$null,$_,$null)} | where {$_ -eq $machineAcc}
if ( !($membershipExists.length -gt 1) )
{
Write-Output("Attempting to add domain: $domainNetbios and Account: $machineAcc")
$objGroup.Add("WinNT://" + $domainNetbios + "/" + $machineAcc)
Write-Output("Account added")
}
Write-Output("Completed setup for broker")
} -ArgumentList $clientURL, $installPath, $domainNetbios | Out-File -Append $Logfile
}
catch [Exception] {
WriteLog("Exception installing the client on the localhost: $($_.Exception.Message)")
throw
}
Write-Output "Setting up Group membership for $compName on SQL"
if(![string]::IsNullOrEmpty($sqlServer)) # only run if $sqlServer is not null
{
SetupGroups $sqlServer $compName $domainNetbios
}
}
Function WriteLog
{
Param ([string]$logstring)
Add-content $Logfile -value $logstring
Write-Host $logstring
}
WriteLog("Starting PostConfig on machine $($localhost)")
if ($existingBroker.ToLower().EndsWith($domainName) -eq $false)
{
$existingBroker = $existingBroker + "." + $domainName
}
if ($clientAccessName.ToLower().EndsWith($domainName) -eq $false)
{
$clientAccessName = $clientAccessName + "." + $domainName
}
#Impersonate user
$ImpersonatedUser = @{}
WriteLog "impersonating as '$username'..."
Add-Type -Namespace Import -Name Win32 -MemberDefinition @'
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string user, string domain, string password, int logonType, int logonProvider, out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
'@
$tokenHandle = 0
$returnValue = [Import.Win32]::LogonUser($userName, $domainName, $password, 2, 0, [ref]$tokenHandle)
if (!$returnValue)
{
$errCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error();
WriteLog "failed a call to LogonUser with error code: $errCode"
throw [System.ComponentModel.Win32Exception]$errCode
}
else
{
$ImpersonatedUser.ImpersonationContext = [System.Security.Principal.WindowsIdentity]::Impersonate($tokenHandle)
[void][Import.Win32]::CloseHandle($tokenHandle)
WriteLog "impersonating user $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) returnValue: '$returnValue'"
}
whoami
SetupCB $localhost $sqlClientUrl
SetupCB $existingBroker $sqlClientUrl
$cb1IP = (Resolve-DnsName -Name $existingBroker -Type A).IPAddress
$cb2IP = (Resolve-DnsName -Name $localhost -Type A).IPAddress
Write-Output("Creating DNS Records")
Invoke-Command -ComputerName $dnsServer -ScriptBlock {
param($domainName, $cb1IP, $cb2IP, $clientAccessName)
$zone = "$domainName"
$name = $clientAccessName.Split('.') | select -First 1
$res= Get-DnsServerResourceRecord -ZoneName $zone -Name $name -EA SilentlyContinue
if ( $res -ne $null ) {
Remove-DnsServerResourceRecord -ZoneName $zone -Name $name -RRType "A" -force
}
$cmd = "Add-DnsServerResourceRecordA -ZoneName $zone -Name $name -AllowUpdateAny -Ipv4Address ""$cb1IP"",""$cb2IP"" -PassThru -TimeToLive 00:00:30"
Write-Output($cmd)
$rec = Invoke-Expression $cmd
if ($rec -eq $null)
{
throw "Unable to add Dns record for ip address $($cb1IP) and $($cb2IP)"
}
Write-Output("Successfully added ip address")
} -ArgumentList $domainName, $cb1IP, $cb2IP, $clientAccessName | Out-File -Append $Logfile
Write-Output("Completed writing DNS Records")
WriteLog("Getting Connection Broker High Availability settings")
$res = Get-RDConnectionBrokerHighAvailability -ConnectionBroker $existingBroker
WriteLog("Result from Get-RDConnectionBrokerHighAvailability: $($res)")
if ($null -eq $res )
{
WriteLog("existingBroker: $($existingBroker)")
WriteLog("primaryDbConnectionString: $($primaryDbConnectionString)")
WriteLog("clientAccessName: $($clientAccessNames)")
Set-RDConnectionBrokerHighAvailability -ConnectionBroker $existingBroker -DatabaseConnectionString $primaryDbConnectionString -ClientAccessName $clientAccessName
WriteLog("Returning from Set-RDConnectionBroker, checking high availability")
$res = Get-RDConnectionBrokerHighAvailability -ConnectionBroker $existingBroker
if ( $null -eq $res )
{
WriteLog "Unable to set the connection broker as high availability"
}
WriteLog("Result from Get-RDConnectionBrokerHighAvailability: $($res)")
}
WriteLog("Getting Connection broker to see if $($localhost) is added as a connection broker")
$res = get-rdserver -ConnectionBroker $existingBroker -Role RDS-CONNECTION-BROKER | select Server
if ( $res.Server.ToLower().StartsWith($localhost.ToLower()) )
{
WriteLog( "$($localhost) is already added as a server")
}
else
{
WriteLog("Add-RdServer -Server $($localhost) -Role RDS-CONNECTION-BROKER")
Add-RdServer -ConnectionBroker $existingBroker -Server $localhost -Role RDS-CONNECTION-BROKER
}
$brokerMachines = GetServersByRole "RoleRdcb"
$rdwaMachines = GetServersByRole "RoleRdwa"
$rdshMachines = GetServersByRole "RoleRdsh"
$rdvhMachines = GetServersByRole "RoleRdvh"
$brokerCount = 1;
$brokerMachineList = "";
foreach ($broker in $brokerMachines)
{
$brokerMachineList = $brokerMachineList + $broker + "." + $env:USERDNSDOMAIN;
if ($brokerCount -lt $brokerMachines.Count)
{
$brokerMachineList = $brokerMachineList + ";"
}
$brokerCount++;
}
foreach ($broker in $brokerMachines)
{
#Write-Host "Setting up Redirector machine : " + $broker
#SetupRDSH $broker;
}
foreach ($rdvh in $rdvhMachines)
{
#Write-Host "Setting up RDVH machine : " + $rdvh
#SetupVMHA $rdvh;
}
foreach ($rdsh in $rdshMachines)
{
#Write-Host "Setting up RDSH machine : " + $rdsh
#SetupRDSH $rdsh;
}
foreach ($rdwa in $rdwaMachines)
{
#Write-Host "Setting up RDWA machine : " + $rdwa
#SetupRDWA $rdwa
}
Writelog "remove impersonation..."
$ImpersonatedUser.ImpersonationContext.Undo()
WriteLog("Completed setup")

Просмотреть файл

@ -0,0 +1,251 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clientAccessName": {
"type": "string",
"defaultValue": "HARDCB",
"metadata": {
"description": "The name of the Connection Broker Servers to be added to the DNS."
}
},
"dnsServer": {
"type": "string",
"defaultValue": "addc-01",
"metadata": {
"description": "The name of the DNS Server to add the DNS entry to for the Connection Broker Names"
}
},
"existingAdminPassword": {
"type": "securestring",
"metadata": {
"description": "The password of the administrator account"
}
},
"existingAdminUsername": {
"type": "string",
"defaultValue": "cloudAdmin",
"metadata": {
"description": "Name of domain user account with administrative priveledges to manage RDS deployment"
}
},
"existingBrokerAvailabilitySet": {
"type": "string",
"defaultValue": "cb-availabilityset",
"metadata": {
"description": "Availability set for RD Connection Brokers"
}
},
"existingBrokerHostname": {
"type": "string",
"defaultValue": "rdcb-01",
"metadata": {
"description": "The host name of the existing Connection Broker vm"
}
},
"existingDomainName": {
"type": "string",
"metadata": {
"description": "The domain to join the Connection Broker Machine to"
}
},
"existingSubnetName": {
"type": "string",
"defaultValue": "Subnet",
"metadata": {
"description": "Subnet name"
}
},
"existingVnetName": {
"type": "string",
"defaultValue": "vnet",
"metadata": {
"description": "Virtual network name"
}
},
"primaryDbConnectionString": {
"type": "string",
"metadata": {
"description": "Specifies the database primary connection string. The database connection string supports both high availability configurations: -- Dedicated database server. Uses Windows Authentication to connect to the databse. -- Shared database server. Uses database authentication (such as SQL authentication) with a user name and password to connect to the database."
}
},
"sqlServer": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The name of the SQL server that the database is located on (only required for the Dedicated database server case w/Windows Auth)"
}
},
"windowsServerVersion": {
"type": "string",
"allowedValues": [
"2012-R2-Datacenter",
"2016-Datacenter"
],
"metadata": {
"description": "Windows server version for the second Broker; should be same version as the first broker in the deployment"
},
"defaultValue": "2016-Datacenter"
},
"_artifactsLocation": {
"type": "string",
"metadata": {
"description": "The base URI where artifacts required by this template are located. When the template is deployed using the accompanying scripts, a private location in the subscription will be used and this value will be automatically generated."
},
"defaultValue": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-deployment-ha-broker/"
}
},
"variables": {
"brokerVmName": "[concat(variables('vmPrefix'), 'rdcb-02')]",
"brokerNicName": "[concat(variables('brokerVmName'), '-nic')]",
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'rdsstorage2')]",
"storageAccountType": "Standard_LRS",
"sqlClientUrl": "http://go.microsoft.com/fwlink/?LinkID=239648&clcid=0x409",
"vmPrefix": "",
"p": {
"broker": "[concat(' -existingBroker ', parameters('existingBrokerHostname'))]",
"connstr": "[concat(' -primaryDbConnectionString \"', parameters('primaryDbConnectionString'), '\"')]",
"domain": "[concat(' -domainName ', parameters('existingDomainName'))]",
"user": "[concat(' -username ', parameters('existingAdminUsername'))]",
"pwd": "[concat(' -password ', parameters('existingAdminPassword'))]",
"can": "[concat(' -clientAccessName \"', parameters('clientAccessName'), '\"')]",
"sqlnclient": "[concat(' -sqlClientUrl \"', variables('sqlClientUrl'), '\"')]",
"dnsserver": "[concat(' -dnsServer ', parameters('dnsServer'))]",
"sqlserver": "[concat(' -sqlServer \"', parameters('sqlServer'), '\"')]"
},
"scriptParameters": "[concat(variables('p').broker, variables('p').connstr, variables('p').domain, variables('p').user, variables('p').pwd, variables('p').can, variables('p').sqlnclient, variables('p').dnsserver, variables('p').sqlserver)]",
"scriptLocation": "[concat(parameters('_artifactsLocation'), '/Scripts')]",
"scriptFileName": "RdcbHaPostConfig.ps1"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"location": "[resourceGroup().location]",
"properties": {
"accountType": "[variables('storageAccountType')]"
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('brokerNicName')]",
"location": "[resourceGroup().location]",
"dependsOn": [],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('existingVnetName'), parameters('existingSubnetName'))]"
}
}
}
]
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('brokerVmName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"[concat('Microsoft.Network/networkInterfaces/', variables('brokerNicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "Standard_A2"
},
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', parameters('existingBrokerAvailabilitySet'))]"
},
"osProfile": {
"computerName": "[variables('brokerVmName')]",
"adminUsername": "[parameters('existingAdminUsername')]",
"adminPassword": "[parameters('existingAdminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "[parameters('windowsServerVersion')]",
"version": "latest"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),'2016-01-01').primaryEndpoints.blob,'vhds/',variables('brokerVmName'),'-osdisk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('brokerNicName'))]"
}
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(variables('brokerVmName'),'/configuration')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines',variables('brokerVmName'))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.75",
"autoUpgradeMinorVersion": true,
"settings": {
"modulesUrl": "[concat(parameters('_artifactsLocation'),'/DSC/Configuration.zip')]",
"configurationFunction": "Configuration.ps1\\DomainJoin",
"properties": {
"domainName": "[parameters('existingDomainName')]",
"adminCreds": {
"UserName": "[parameters('existingAdminUsername')]",
"Password": "PrivateSettingsRef:adminPassword"
}
}
},
"protectedSettings": {
"Items": {
"adminPassword": "[parameters('existingAdminPassword')]"
}
}
}
},
{
"apiVersion": "2015-06-15",
"name": "[concat(variables('brokerVmName'),'/ha-broker-configuration')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('brokerVmName'),'/extensions/','configuration')]"
],
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(variables('scriptLocation'), '/', variables('scriptFileName'))]"
]
},
"protectedSettings": {
"commandToExecute": "[concat( 'powershell -noninteractive -executionpolicy bypass -file ', variables('scriptFileName'), variables('scriptParameters'), ' >> script.log 2>&1' )]"
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,45 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"_artifactsLocation": {
"value": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-deployment-ha-broker/"
},
"clientAccessName": {
"value": "HARDCB"
},
"dnsServer": {
"value": "addc-01"
},
"existingAdminPassword": {
"value": "{enter_existing_adminUsername_password_here}"
},
"existingAdminUsername": {
"value": "cloudadmin"
},
"existingBrokerAvailabilitySet": {
"value": "cb-availabilityset"
},
"existingBrokerHostname": {
"value": "rdcb-01"
},
"existingDomainName": {
"value": "contoso.com"
},
"existingSubnetName": {
"value": "subnet"
},
"existingVnetName": {
"value": "vnet"
},
"primaryDbConnectionString": {
"value": "DRIVER=SQL Server Native Client 11.0;Server={enter_sql_server_here},1433;Database={enter_sql_database_here};Uid={enter_sql_admin_here}@{enter_sql_server_here};Pwd={enter_sql_password_here};Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;"
},
"sqlServer": {
"value": "{enter_NON_Azure_sql_server_here_or_leave_blank_for_Azure_SQL}"
},
"windowsServerVersion": {
"value": "2016-Datacenter"
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"itemDisplayName": "RDS Broker High Availability deployment",
"description": "This template provides high availability to RD Connection Broker in an existing RDS deployment",
"summary": "Provide HA to RDCB servers in RDS deployment",
"githubUsername": "fberson",
"dateUpdated": "2017-07-21"
}

Двоичные данные
rds-deployment-ha-gateway/Configuration.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,45 @@
# Provide High Availability to RD Gateway and RD Web Access servers in RDS deployment
This template deploys the following resources:
* a number of RD Gateway/RD Web Access VMs (number defined by 'numberOfWebGwInstances' parameter)
The template will
* Join all new VMs to the domain
* Deploy RDS roles in the deployment
* Join new VM's to the existing web and Gateway farm of basic RDS deployment
* Post configurations for web/Gateway VM's such as defining the Machine keys for IIS modules
### Prerequisites
Current Template is an extension to the Basic RDS Deployment Template, and it is mandatory to deploy any one of the template as prerequisite:
* Basic RDS deployment template
https://github.com/Azure/azure-quickstart-templates/tree/master/rds-deployment
* RDS deployment from custom RDSH image
https://github.com/Azure/azure-quickstart-templates/tree/master/rds-deployment-custom-image-rdsh
* RDS deployment on pre-existing VNET and AD
https://github.com/Azure/azure-quickstart-templates/tree/master/rds-deployment-existing-ad
This template expects the same names of resources from RDS deployment, if resource names are changed in your deployment then please edit the parameters and resources accordingly, example of such resources are below:
<ul>
<li>storageAccountName: Resource must be exact same to existing RDS deployment.</li>
<li>publicIpRef: Resource must be exact same to existing RDS deployment.</li>
<li>availabilitySets: Resource must be exact same to existing RDS deployment.</li>
<li>Load-balancer: Load balancer name, Backend pool, LB-rules, Nat-Rule and NIC.</li>
<li>VMs – VM name classification which is using copy index function.</li>
<li>NIC – NIC naming convention.</li>
</ul>
Click the button below to deploy
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Frds-deployment-ha-gateway%2Fazuredeploy.json" target="_blank">
<img src="http://azuredeploy.net/deploybutton.png"/>
</a>
<a href="http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Frds-deployment-ha-gateway%2Fazuredeploy.json" target="_blank">
<img src="http://armviz.io/visualizebutton.png"/>
</a>

Просмотреть файл

@ -0,0 +1,312 @@

param
(
[String]$WebGwServer,
[String]$BrokerServer,
[String]$WebURL,
[String]$Domainname,
[String]$DomainNetbios,
[String]$username,
[String]$password,
[string]$ServerName = "gateway",
[int]$numberofwebServers,
$validationKey64,
$decryptionKey24
)
$localhost = [System.Net.Dns]::GetHostByName((hostname)).HostName
$username = $DomainNetbios + "\" + $Username
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList @($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
configuration RDWebAccessdeployment
{
param
(
[Parameter(Mandatory)]
[String]$domainName,
[Parameter(Mandatory)]
[PSCredential]$adminCreds,
# Connection Broker Node name
[String]$connectionBroker,
# Web Access Node name
[String]$webAccessServer,
# Gateway external FQDN
[String]$externalFqdn
)
Import-DscResource -ModuleName PSDesiredStateConfiguration -ModuleVersion 1.1
Import-DscResource -ModuleName xActiveDirectory, xComputerManagement, xRemoteDesktopSessionHost
$localhost = [System.Net.Dns]::GetHostByName((hostname)).HostName
if (-not $connectionBroker) { $connectionBroker = $localhost }
if (-not $webAccessServer) { $webAccessServer = $localhost }
if (-not $collectionName) { $collectionName = "Desktop Collection" }
if (-not $collectionDescription) { $collectionDescription = "A sample RD Session collection up in cloud." }
Node localhost
{
LocalConfigurationManager
{
RebootNodeIfNeeded = $true
ConfigurationMode = "ApplyOnly"
}
xRDServer AddWebAccessServer
{
Role = 'RDS-Web-Access'
Server = $webAccessServer
GatewayExternalFqdn = $externalFqdn
ConnectionBroker = $BrokerServer
PsDscRunAsCredential = $adminCreds
}
}
}#End of Configuration RDWebAccessdeployment
$ConfigData = @{
AllNodes = @(
@{
NodeName = 'localhost'
PSDscAllowPlainTextPassword = $true
}
)
} # End of Config Data
# calling the configuration
RDWebAccessdeployment -adminCreds $cred -connectionBroker $BrokerServer -webAccessServer $localhost -externalFqdn $WebURL -domainName $Domainname -ConfigurationData $ConfigData -Verbose
Start-DscConfiguration -Wait -Force -Path .\RDWebAccessdeployment -Verbose
configuration RDGatewaydeployment
{
param
(
[Parameter(Mandatory)]
[String]$domainName,
[Parameter(Mandatory)]
[PSCredential]$adminCreds,
# Connection Broker Node name
[String]$connectionBroker,
# Web Access Node name
[String]$webAccessServer,
# Gateway external FQDN
[String]$externalFqdn,
# RD Session Host count and naming prefix
[Int]$numberOfRdshInstances = 1,
[String]$sessionHostNamingPrefix = "SessionHost-",
# Collection Name
[String]$collectionName,
# Connection Description
[String]$collectionDescription
)
Import-DscResource -ModuleName PSDesiredStateConfiguration -ModuleVersion 1.1
Import-DscResource -ModuleName xActiveDirectory, xComputerManagement, xRemoteDesktopSessionHost
$localhost = [System.Net.Dns]::GetHostByName((hostname)).HostName
if (-not $connectionBroker) { $connectionBroker = $localhost }
if (-not $webAccessServer) { $webAccessServer = $localhost }
if (-not $collectionName) { $collectionName = "Desktop Collection" }
if (-not $collectionDescription) { $collectionDescription = "A sample RD Session collection up in cloud." }
Node localhost
{
LocalConfigurationManager
{
RebootNodeIfNeeded = $true
ConfigurationMode = "ApplyOnly"
}
xRDServer AddGatewayServer
{
Role = 'RDS-Gateway'
Server = $webAccessServer
GatewayExternalFqdn = $externalFqdn
ConnectionBroker = $BrokerServer
PsDscRunAsCredential = $adminCreds
}
}
}#End of Configuration RDGatewaydeployment
$ConfigData = @{
AllNodes = @(
@{
NodeName = 'localhost'
PSDscAllowPlainTextPassword = $true
}
)
} # End of Config Data
RDGatewaydeployment -adminCreds $cred -connectionBroker $BrokerServer -webAccessServer $localhost -externalFqdn $WebURL -domainName $Domainname -ConfigurationData $ConfigData -Verbose
Start-DscConfiguration -Wait -Force -Path .\RDGatewaydeployment -Verbose
#--Post Configuration for IIS RD web for Machine keys
Write-Host "Username : $($username), Password: $($password)"
#$username = $DomainNetbios + "\" + $username
#$cred = New-Object System.Management.Automation.PSCredential -ArgumentList @($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
$webServernameArray = New-Object System.Collections.ArrayList
for ($i = 0; $i -le $numberofwebServers; $i++)
{
if ($i -eq 0)
{
$webServername = "Gateway"
#Write-Host "For i = 0, srvername = $($webServername)"
}
else{
$servercount = $i - 1
$webServername = "gateway" + $servercount.ToString()
#Write-Host "For $($i), servername = $($webServername)"
}
$webServernameArray.Add($webServername) | Out-Null
}
Write-Host "web server Array value $($webServernameArray)"
# genrate 64 and 24 char keys:
[int]$keylen = 64
$buff = new-object "System.Byte[]" $keylen
$rnd = new-object System.Security.Cryptography.RNGCryptoServiceProvider
$rnd.GetBytes($buff)
$result =""
for($i=0; $i -lt $keylen; $i++) {
$result += [System.String]::Format("{0:X2}",$buff[$i])
}
$validationkey64 = $result
# Write-Host $validationkey64
# end of Validation Key code
$keylen = 24
$buff1 = new-object "System.Byte[]" $keylen
$rnd1 = new-object System.Security.Cryptography.RNGCryptoServiceProvider
$rnd1.GetBytes($buff1)
$result =""
for($i=0; $i -lt $keylen; $i++) {
$result += [System.String]::Format("{0:X2}",$buff[$i])
}
$decryptionKey24 = $result
# Write-Host $decryptionKey24
# logic end for 64 and 24 char keys
foreach ($item in $webServernameArray)
{
$WebServer = $item + "." + $DomainName
Write-Host "Starting working on webserver name : $($WebServer)"
try{
$session = New-PSSession -ComputerName $WebServer -Credential $cred
}
catch{
Write-Host $Error
}
Invoke-Command -session $session -ScriptBlock {param($validationkey64,$decryptionKey24)
function ValidateWindowsFeature
{
$localhost = [System.Net.Dns]::GetHostByName((hostname)).HostName
$RdsWindowsFeature = Get-WindowsFeature -ComputerName $localhost -Name RDS-Web-Access
if ($RdsWindowsFeature.InstallState -eq "Installed")
{
Return $true
}
else
{
Return $false
}
}
$Validationheck = $False
$Validationheck = ValidateWindowsFeature
$localhost = [System.Net.Dns]::GetHostByName((hostname)).HostName
if($Validationheck -eq $true)
{
Write-Host "Windows feature RDS-Web_access present on $($localhost)"
$machineConfig = "C:\Windows\Web\RDWeb\Web.config"
if (Test-Path $machineConfig)
{
Write-Host "editing machine config file : $($machineConfig) on server $($localhost) "
try{
$xml = [xml](get-content $machineConfig)
$xml.Save($machineConfig + "_")
$root = $xml.get_DocumentElement()
$system_web = $root."system.web"
if ($system_web.machineKey -eq $null)
{
$machineKey = $xml.CreateElement("machineKey")
$a = $system_web.AppendChild($machineKey)
}
$system_web.SelectSingleNode("machineKey").SetAttribute("validationKey","$validationKey64")
$system_web.SelectSingleNode("machineKey").SetAttribute("decryptionKey","$decryptionKey24")
$a = $xml.Save($machineConfig)
}
Catch{
Write-Host $Error
}
} # end of If test-path
} # End of If($ValidationCheck -eq $True)
else
{
Write-Host "Windows feature RDS-Web_access is not present on $($localhost)"
}
} -ArgumentList $validationKey64,$decryptionKey24 # end of Script Block
Remove-PSSession -Session $session
} # end of foreach $item in $webServername

Просмотреть файл

@ -0,0 +1,401 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"dnsLabelPrefix": {
"type": "string",
"metadata": {
"description": "Unique public DNS prefix for the deployment. The fqdn will look something like '<dnsname>.westus.cloudapp.azure.com'. Up to 62 chars, digits or dashes, lowercase, should start with a letter: must conform to '^[a-z][a-z0-9-]{1,61}[a-z0-9]$'."
}
},
"loadBalancer": {
"type": "string",
"metadata": {
"description": "The Loadbalancer name must match from the RDS deployment. And default value taken by template is loadbalancer."
},
"defaultValue": "loadBalancer"
},
"backendAddressPools": {
"type": "string",
"defaultValue": "LBBAP",
"metadata": {
"description": "The backendAddressPools name must match from the RDS deployment. And default value taken by template is LBBAP."
}
},
"gw-AvailabilitySet": {
"type": "string",
"defaultValue": "gw-availabilityset",
"metadata": {
"description": "The gw-availabilityset name must match from the RDS deployment. And default value taken by template is gw-availabilityset."
}
},
"adDomainName": {
"type": "string",
"metadata": {
"description": "The FQDN of the AD domain"
}
},
"adminUsername": {
"type": "string",
"metadata": {
"description": "The name of the administrator of the new VM and the domain. Exclusion list: 'administrator"
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "The password for the administrator account of the new VM and the domain"
}
},
"numberOfWebGwInstances": {
"type": "int",
"defaultValue": 2,
"metadata": {
"description": "Number of RD Gateway instances"
}
},
"brokerServer": {
"type": "string",
"metadata": {
"description": "FQDN for Broker Server"
}
},
"WebURL": {
"type": "string",
"metadata": {
"description": "This is RD Gateway external FQDN. This shall be picked from existing basic RDS deploment."
}
},
"domainNetbios": {
"type": "string",
"metadata": {
"description": "Netbios Name for Domain"
}
},
"storageAccountName": {
"type": "string",
"metadata": {
"description": "Storage account name of RDS-Deployment"
}
},
"imageSKU": {
"type": "string",
"allowedValues": [
"2012-R2-Datacenter",
"2016-Datacenter"
],
"metadata": {
"description": "Windows server SKU"
},
"defaultValue": "2016-Datacenter"
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_A2",
"metadata": {
"description": "Size for the new RD Gateway VMs"
}
},
"existingVnet": {
"type": "string",
"metadata": {
"description": "The vnet name of AD domain. For example johnvnet1"
},
"defaultValue": "vnet"
},
"existingSubnet": {
"type": "string",
"metadata": {
"description": "The subnet name of AD domain. For example johnsubnet1"
},
"defaultValue": "Subnet"
}
},
"variables": {
"imagePublisher": "MicrosoftWindowsServer",
"imageOffer": "WindowsServer",
"vnetAddressRange": "10.0.0.0/16",
"subnetAddressRange": "10.0.0.0/24",
"dnsServerPrivateIp": "10.0.0.8",
"subnet-id": "[concat(resourceId('Microsoft.Network/virtualNetworks',parameters('existingVnet')),'/subnets/',parameters('existingSubnet'))]",
"publicIpRef": "publicIp",
"assetLocation": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-deployment",
"apiVersion": "2015-06-15",
"PublicIPLocation": "[concat(parameters('dnsLabelPrefix'),'.','[resourceGroup().location]','.cloudapp.azure.com')]"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"location": "[resourceGroup().location]",
"properties": {
"accountType": "Standard_LRS"
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "[Parameters('gw-availabilityset')]",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIpRef')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/loadBalancers",
"name": "[Parameters('Loadbalancer')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/',variables('publicIpRef'))]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "LBFE",
"properties": {
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIpRef'))]"
}
}
}
],
"backendAddressPools": [
{
"name": "[parameters('backendAddressPools')]"
}
],
"loadBalancingRules": [
{
"name": "LBRule01",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers',Parameters('loadBalancer')),'/frontendIPConfigurations/LBFE')]"
},
"backendAddressPool": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers',Parameters('loadBalancer')),'/backendAddressPools/',parameters('backendAddressPools'))]"
},
"protocol": "Tcp",
"frontendPort": 443,
"backendPort": 443,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"loadDistribution": "SourceIPProtocol",
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers',Parameters('loadBalancer')),'/probes/tcpProbe')]"
}
}
},
{
"name": "LBRule02",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers',Parameters('loadBalancer')),'/frontendIPConfigurations/LBFE')]"
},
"backendAddressPool": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers',Parameters('loadBalancer')),'/backendAddressPools/',parameters('backendAddressPools'))]"
},
"protocol": "Tcp",
"frontendPort": 3391,
"backendPort": 3391,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"loadDistribution": "SourceIPProtocol",
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers',Parameters('loadBalancer')),'/probes/tcpProbe')]"
}
}
}
],
"probes": [
{
"name": "tcpProbe",
"properties": {
"protocol": "Tcp",
"port": 443,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "tcpProbe01",
"properties": {
"protocol": "Tcp",
"port": 3391,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
],
"inboundNatRules": [
{
"name": "rdp",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers',Parameters('loadBalancer')),'/frontendIPConfigurations/LBFE')]"
},
"protocol": "tcp",
"frontendPort": 3389,
"backendPort": 3389,
"enableFloatingIP": false
}
}
]
}
},
{
"name": "[concat('gw-',copyindex(),'-nic')]",
"type": "Microsoft.Network/networkInterfaces",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"copy": {
"name": "gw-nic-loop",
"count": "[parameters('numberOfWebGwInstances')]"
},
"dependsOn": [
"Microsoft.Network/loadBalancers/loadBalancer"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnet-id')]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[concat(resourceId('Microsoft.Network/loadBalancers','loadBalancer'),'/backendAddressPools/',parameters('backendAddressPools'))]"
}
],
"loadBalancerInboundNatRules": []
}
}
]
}
},
{
"name": "[concat('gw-vm-',copyindex())]",
"type": "Microsoft.Compute/virtualMachines",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"copy": {
"name": "gw-vm-loop",
"count": "[parameters('numberOfWebGwInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]",
"[resourceId('Microsoft.Compute/availabilitySets', 'gw-availabilityset')]",
"[concat('Microsoft.Network/networkInterfaces/gw-',copyindex(),'-nic')]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', 'gw-availabilityset')]"
},
"osProfile": {
"computerName": "[concat('gateway',copyindex())]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[parameters('imageSKU')]",
"version": "latest"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName')),'2016-01-01').primaryEndpoints.blob,'/vhds/gateway',copyindex(),'-osdisk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat('gw-',copyindex(),'-nic'))]"
}
]
}
},
"resources": [
{
"name": "[concat('gw-vm-',copyindex(),'/Gateway')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', Concat('gw-vm-',copyindex()))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.75",
"autoUpgradeMinorVersion": true,
"settings": {
"ModulesUrl": "[concat(variables('assetLocation'),'/Configuration.zip')]",
"ConfigurationFunction": "Configuration.ps1\\Gateway",
"properties": {
"DomainName": "[parameters('adDomainName')]",
"AdminCreds": {
"UserName": "[parameters('adminUsername')]",
"Password": "PrivateSettingsRef:AdminPassword"
}
}
},
"protectedSettings": {
"Items": {
"AdminPassword": "[parameters('adminPassword')]"
}
}
}
},
{
"name": "[concat('gw-vm-',copyindex(),'/WebAndGwFarmAdd_PostConfig1.1')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', Concat('gw-vm-',copyindex()))]",
"[concat('Microsoft.Compute/virtualMachines/gw-vm-',copyindex(),'/extensions/','Gateway')]"
],
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-deployment-ha-gateway/Scripts/WebAndGwFarmAdd_PostConfig1.1.ps1"
]
},
"protectedSettings": {
"Items": {
"AdminPassword": "[parameters('adminPassword')]"
},
"storageAccountName": "[parameters('storageaccountname')]",
"commandToExecute": "[Concat('powershell.exe -ExecutionPolicy Unrestricted -File', ' ', 'WebAndGwFarmAdd_PostConfig1.1.ps1',' ','-username \"',parameters('adminusername'),'\" ', '-password \"',parameters('adminpassword'),'\" ','-BrokerServer \"',parameters('BrokerServer'),'\" ','-WebURL \"',parameters('WebURL'),'\" ','-Domainname \"',parameters('adDomainName'),'\" ','-DomainNetbios \"',parameters('DomainNetbios'),'\" ','-numberofwebServers ',parameters('numberOfWebGwInstances'))]"
}
}
}
]
}
]
}

Просмотреть файл

@ -0,0 +1,48 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminPassword": {
"value": "GEN-PASSWORD"
},
"adminUsername": {
"value": "GEN-USER"
},
"adDomainName": {
"value": "mydomain.local"
},
"numberOfWebGwInstances": {
"value": 2
},
"brokerServer": {
"value": "Broker.Mydomain.local"
},
"WebURL": {
"value": "RDS-WebURL"
},
"domainNetbios": {
"value": "Mydomain"
},
"dnsLabelPrefix": {
"value": "GEN-UNIQUE"
},
"storageAccountName": {
"value": "GEN-UNIQUE"
},
"gw-availabilityset": {
"value": "gw-availabilityset"
},
"loadBalancer": {
"value": "loadBalancer"
},
"backendAddressPools": {
"value": "LBBAP"
},
"existingVnet": {
"value": "vnet"
},
"existingSubnet": {
"value": "Subnet"
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"itemDisplayName": "RDS Gateway High Availability deployment",
"description": "This template provides high availability to RD Gateway and RD Web Access servers in an existing RDS deployment",
"summary": "Provide HA to RDG and RDWA servers in RDS deployment",
"githubUsername": "ashishsharma303",
"dateUpdated": "2016-12-21"
}

Двоичные данные
rds-deployment/Configuration.zip Normal file

Двоичный файл не отображается.

16
rds-deployment/README.md Normal file
Просмотреть файл

@ -0,0 +1,16 @@
# Create Remote Desktop Sesson Collection deployment
This template deploys the following resources:
<ul><li>storage account;</li><li>vnet, public ip, load balancer;</li><li>domain controller vm;</li><li>RD Gateway/RD Web Access vm;</li><li>RD Connection Broker/RD Licensing Server vm;</li><li>a number of RD Session hosts (number defined by 'numberOfRdshInstances' parameter)</li></ul>
The template will deploy DC, join all vms to the domain and configure RDS roles in the deployment.
Click the button below to deploy
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Frds-deployment%2Fazuredeploy.json" target="_blank">
<img src="http://azuredeploy.net/deploybutton.png"/>
</a>
<a href="http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Frds-deployment%2Fazuredeploy.json" target="_blank">
<img src="http://armviz.io/visualizebutton.png"/>
</a>

Просмотреть файл

@ -0,0 +1,855 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"gwdnsLabelPrefix": {
"type": "string",
"metadata": {
"description": "Unique gateway public DNS prefix for the deployment. The fqdn will look something like '<dnsname>.westus.cloudapp.azure.com'. Up to 62 chars, digits or dashes, lowercase, should start with a letter: must conform to '^[a-z][a-z0-9-]{1,61}[a-z0-9]$'. For example johndns1 will result the final RDWEB access url like https://johndns1.westus.cloudapp.azure.com/RDWeb"
}
},
"gwpublicIPAddressName": {
"type": "string",
"metadata": {
"description": "The name of gateway PublicIPAddress object"
},
"defaultValue": "gwpip"
},
"adDomainName": {
"type": "string",
"metadata": {
"description": "The name of the AD domain. For example contoso.com"
},
"defaultValue": "contoso.com"
},
"adminUsername": {
"type": "string",
"metadata": {
"description": "The name of the administrator of the new VM and the domain. Exclusion list: 'administrator'. For example johnadmin"
},
"defaultValue": "vmadmin"
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "The password for the administrator account of the new VM and the domain"
},
"defaultValue": "[concat('Subscription#',subscription().subscriptionId)]"
},
"imageSKU": {
"type": "string",
"allowedValues": [
"2012-R2-Datacenter",
"2016-Datacenter"
],
"metadata": {
"description": "Windows server SKU"
},
"defaultValue": "2016-Datacenter"
},
"numberOfRdshInstances": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Number of RemoteDesktopSessionHosts"
}
},
"rdshVmSize": {
"type": "string",
"allowedValues": [
"Standard_A0",
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D5"
],
"metadata": {
"description": "The size of the RDSH VMs"
},
"defaultValue": "Standard_A4"
}
},
"variables": {
"adAssetLocation": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/ad-non-ha",
"adVMSize": "Standard_A1",
"adVnetName": "[concat('ADVNET',resourceGroup().name)]",
"adSubnetName": "[concat('ADStaticSubnet',resourceGroup().name)]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', variables('adVnetName'))]",
"staticSubnetID": "[concat(variables('vnetID'),'/subnets/', variables('adSubnetName'))]",
"adTemplateURL": "[concat(variables('adAssetLocation'),'/adVmTemplate.json')]",
"adStorageName": "[tolower(concat('adsa',uniqueString(resourceGroup().id)))]",
"adVmDeployment": "CreateAdVms",
"adVmDeploymentId": "[concat('Microsoft.Resources/deployments/', variables('adVmDeployment'))]",
"deployPrimaryAdTemplateURL": "[concat(variables('adAssetLocation'),'/deployPrimaryAD.json')]",
"deployPrimaryAd": "DeployPrimaryAd",
"deployPrimaryAdID": "[concat('Microsoft.Resources/deployments/', variables('deployPrimaryAd'))]",
"adPDCVMName": "advm",
"vnetwithDNSTemplateURL": "[concat(variables('adAssetLocation'),'/vnet-with-dns-server.json')]",
"updateVNetDNS1": "updateVNetDNS",
"updateVNetDNS1ID": "[concat('Microsoft.Resources/deployments/', variables('updateVNetDNS1'))]",
"nicTemplateURL": "[concat(variables('adAssetLocation'),'/nic.json')]",
"publicLBName": "[concat('ADPLB',resourceGroup().name)]",
"publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]",
"lbFE": "ADLBFE",
"rdpNAT": "ADRDPNAT",
"publiclbID": "[resourceId('Microsoft.Network/loadBalancers',variables('publicLBName'))]",
"publiclbFEConfigID": "[concat(variables('publiclbID'),'/frontendIPConfigurations/',variables('lbFE'))]",
"rdpPort": 3389,
"adRDPNATRuleID": "[concat(variables('publiclbID'),'/inboundNatRules/',variables('rdpNAT'))]",
"adNICName": "[concat('ADNic',resourceGroup().name)]",
"lbBE": "ADLBBE",
"publicBEAddressPoolID": "[concat(variables('publiclbID'),'/backendAddressPools/',variables('lbBE'))]",
"gwLBName": "[concat('GWPLB',resourceGroup().name)]",
"publicIPAddressName": "[tolower(concat('adpip',uniqueString(resourceGroup().Id)))]",
"gwIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',parameters('gwpublicIPAddressName'))]",
"gwlbFE": "GWLBFE",
"gwlbID": "[resourceId('Microsoft.Network/loadBalancers',variables('gwLBName'))]",
"gwlbFEConfigID": "[concat(variables('gwlbID'),'/frontendIPConfigurations/',variables('gwlbFE'))]",
"gwlbBE": "GWLBBE",
"gwBEAddressPoolID": "[concat(variables('gwlbID'),'/backendAddressPools/',variables('gwlbBE'))]",
"dnsLabelPrefix": "[tolower(concat('adns', resourceGroup().name))]",
"storageAccountName": "[tolower(concat('rdsa',uniqueString(resourceGroup().id)))]",
"storageAccountType": "Standard_LRS",
"uniqueStorageAccountContainerName": "[tolower(concat('sc', uniqueString(resourceGroup().id)))]",
"imagePublisher": "MicrosoftWindowsServer",
"imageOffer": "WindowsServer",
"vnetAddressRange": "10.0.0.0/16",
"subnetAddressRange": "10.0.0.0/24",
"dnsServerPrivateIp": "10.0.0.4",
"subnet-id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('adVnetName')),'/subnets/', variables('adSubnetName'))]",
"assetLocation": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-deployment/",
"nsgName": "RDSNsg",
"nsgID": "[resourceId('Microsoft.Network/networkSecurityGroups',variables('nsgName'))]",
"subnets": [
{
"name": "[variables('adSubnetName')]",
"properties": {
"addressPrefix": "[variables('subnetAddressRange')]",
"networkSecurityGroup": {
"id": "[variables('nsgID')]"
}
}
}
]
},
"resources": [
{
"name": "[variables('nsgName')]",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"properties": {
"securityRules": [
{
"name": "rule1",
"properties": {
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 101,
"direction": "Inbound"
}
}
]
}
},
{
"name": "[variables('adVnetName')]",
"type": "Microsoft.Network/virtualNetworks",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[variables('nsgID')]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('vnetAddressRange')]"
]
},
"subnets": [
{
"name": "[variables('adSubnetName')]",
"properties": {
"addressPrefix": "[variables('subnetAddressRange')]",
"networkSecurityGroup": {
"id": "[variables('nsgID')]"
}
}
}
]
}
},
{
"name": "[variables('publicIPAddressName')]",
"type": "Microsoft.Network/publicIPAddresses",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[variables('vnetID')]"
],
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[variables('dnsLabelPrefix')]"
}
}
},
{
"name": "[parameters('gwpublicIPAddressName')]",
"type": "Microsoft.Network/publicIPAddresses",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[variables('deployPrimaryAdID')]"
],
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('gwdnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "gw-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "cb-availabilityset",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "rdsh-availabilityset",
"location": "[resourceGroup().location]"
},
{
"name": "[variables('publiclbName')]",
"type": "Microsoft.Network/loadBalancers",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('publicIPAddressID')]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "[variables('lbFE')]",
"properties": {
"publicIPAddress": {
"id": "[variables('publicIPAddressID')]"
}
}
}
],
"backendAddressPools": [
{
"name": "[variables('lbBE')]"
}
],
"inboundNatRules": [
{
"name": "[variables('rdpNAT')]",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('publiclbFEConfigID')]"
},
"protocol": "tcp",
"frontendPort": "[variables('rdpPort')]",
"backendPort": 3389,
"enableFloatingIP": false
}
}
]
}
},
{
"name": "[variables('gwlbName')]",
"type": "Microsoft.Network/loadBalancers",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('gwIPAddressID')]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "[variables('gwlbFE')]",
"properties": {
"publicIPAddress": {
"id": "[variables('gwIPAddressID')]"
}
}
}
],
"backendAddressPools": [
{
"name": "[variables('gwlbBE')]"
}
],
"loadBalancingRules": [
{
"name": "LBRule01",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('gwlbFEConfigID')]"
},
"backendAddressPool": {
"id": "[variables('gwBEAddressPoolID')]"
},
"protocol": "Tcp",
"frontendPort": 443,
"backendPort": 443,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"loadDistribution": "SourceIPProtocol",
"probe": {
"id": "[concat(variables('gwlbID'),'/probes/tcpProbe')]"
}
}
},
{
"name": "LBRule02",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('gwlbFEConfigID')]"
},
"backendAddressPool": {
"id": "[variables('gwBEAddressPoolID')]"
},
"protocol": "Udp",
"frontendPort": 3391,
"backendPort": 3391,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"loadDistribution": "SourceIPProtocol",
"probe": {
"id": "[concat(variables('gwlbID'),'/probes/tcpProbe01')]"
}
}
}
],
"probes": [
{
"name": "tcpProbe",
"properties": {
"protocol": "Tcp",
"port": 443,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "tcpProbe01",
"properties": {
"protocol": "Tcp",
"port": 3391,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
],
"inboundNatRules": [
{
"name": "rdp",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('gwlbFEConfigID')]"
},
"protocol": "tcp",
"frontendPort": 3389,
"backendPort": 3389,
"enableFloatingIP": false
}
}
]
}
},
{
"name": "[variables('adVmDeployment')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-02-01",
"dependsOn": [
"[variables('publiclbID')]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[variables('adTemplateURL')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"adminUsername": {
"value": "[parameters('adminUsername')]"
},
"adminPassword": {
"value": "[parameters('adminPassword')]"
},
"adRDPNATRuleID": {
"value": "[variables('adRDPNATRuleID')]"
},
"storageAccount": {
"value": "[variables('adStorageName')]"
},
"subnetResourceId": {
"value": "[variables('staticSubnetID')]"
},
"primaryAdIpAddress": {
"value": "[variables('dnsServerPrivateIp')]"
},
"storageAccountType": {
"value": "[variables('storageAccountType')]"
},
"vmName": {
"value": "[variables('adPDCVMName')]"
},
"vmSize": {
"value": "[variables('adVMSize')]"
},
"adDNicName": {
"value": "[variables('adNICName')]"
}
}
}
},
{
"name": "[variables('deployPrimaryAd')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-02-01",
"dependsOn": [
"[variables('adVmDeploymentID')]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[variables('deployPrimaryAdTemplateURL')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"primaryADName": {
"value": "[variables('adPDCVMName')]"
},
"domainName": {
"value": "[parameters('adDomainName')]"
},
"adminUsername": {
"value": "[parameters('adminUsername')]"
},
"adminPassword": {
"value": "[parameters('adminPassword')]"
},
"assetLocation": {
"value": "[variables('adAssetLocation')]"
}
}
}
},
{
"name": "[variables('updateVNetDNS1')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-02-01",
"dependsOn": [
"[variables('deployPrimaryAdID')]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[variables('vnetwithDNSTemplateURL')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"virtualNetworkName": {
"value": "[variables('adVnetName')]"
},
"virtualNetworkAddressRange": {
"value": "[variables('vnetAddressRange')]"
},
"subnets": {
"value": "[variables('subnets')]"
},
"dnsServerAddress": {
"value": [
"[variables('dnsServerPrivateIp')]"
]
}
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"location": "[resourceGroup().location]",
"properties": {
"accountType": "[variables('storageAccountType')]"
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "gw-nic",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('gwlbID')]",
"[variables('adVmDeploymentID')]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnet-id')]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[variables('gwBEAddressPoolID')]"
}
],
"loadBalancerInboundNatRules": [
{
"id": "[concat(variables('gwlbID'),'/inboundNatRules/rdp')]"
}
]
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "cb-nic",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('publiclbID')]",
"[variables('adVmDeploymentID')]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnet-id')]"
}
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat('rdsh-', copyindex(), '-nic')]",
"location": "[resourceGroup().location]",
"copy": {
"name": "rdsh-nic-loop",
"count": "[parameters('numberOfRdshInstances')]"
},
"dependsOn": [
"[variables('publiclbID')]",
"[variables('adVmDeploymentID')]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('subnet-id')]"
}
}
}
],
"dnsSettings": {
"dnsServers": [
"[variables('dnsServerPrivateIp')]"
]
}
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines",
"name": "gw-vm",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('deployPrimaryAdID')]",
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"Microsoft.Network/networkInterfaces/gw-nic"
],
"properties": {
"hardwareProfile": {
"vmSize": "Standard_A2"
},
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', 'gw-availabilityset')]"
},
"osProfile": {
"computerName": "gateway",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[parameters('imageSKU')]",
"version": "latest"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),'2016-01-01').primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','gw-vm-os-disk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces','gw-nic')]"
}
]
}
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "gw-vm/gateway",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', 'gw-vm')]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.11",
"autoUpgradeMinorVersion": true,
"settings": {
"modulesUrl": "[concat(variables('assetLocation'),'/Configuration.zip')]",
"configurationFunction": "Configuration.ps1\\Gateway",
"Properties": {
"DomainName": "[parameters('adDomainName')]",
"AdminCreds": {
"UserName": "[parameters('adminUsername')]",
"Password": "PrivateSettingsRef:AdminPassword"
}
}
},
"protectedSettings": {
"Items": {
"AdminPassword": "[parameters('adminPassword')]"
}
}
}
}
]
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat('rdsh-', copyindex())]",
"location": "[resourceGroup().location]",
"copy": {
"name": "rdsh-vm-loop",
"count": "[parameters('numberOfRdshInstances')]"
},
"dependsOn": [
"[variables('deployPrimaryAdID')]",
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"[concat('Microsoft.Network/networkInterfaces/', 'rdsh-', copyindex(), '-nic')]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('rdshVmSize')]"
},
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', 'rdsh-availabilityset')]"
},
"osProfile": {
"computerName": "[concat('rdsh-', copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[parameters('imageSKU')]",
"version": "latest"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),'2016-01-01').primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','rdsh-',copyindex(),'-os-disk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat('rdsh-', copyindex(), '-nic'))]"
}
]
}
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat('rdsh-', copyindex(),'/sessionhost')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat('rdsh-', copyindex()))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.11",
"autoUpgradeMinorVersion": true,
"settings": {
"ModulesUrl": "[concat(variables('assetLocation'),'/Configuration.zip')]",
"ConfigurationFunction": "Configuration.ps1\\SessionHost",
"Properties": {
"DomainName": "[parameters('adDomainName')]",
"AdminCreds": {
"UserName": "[parameters('adminUsername')]",
"Password": "PrivateSettingsRef:AdminPassword"
}
}
},
"protectedSettings": {
"Items": {
"AdminPassword": "[parameters('adminPassword')]"
}
}
}
}
]
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines",
"name": "cb-vm",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('deployPrimaryAdID')]",
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"Microsoft.Network/networkInterfaces/cb-nic",
"rdsh-vm-loop"
],
"properties": {
"hardwareProfile": {
"vmSize": "Standard_A2"
},
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', 'cb-availabilityset')]"
},
"osProfile": {
"computerName": "broker",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[parameters('imageSKU')]",
"version": "latest"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')),'2016-01-01').primaryEndpoints.blob,variables('uniqueStorageAccountContainerName'),'/','cb-vm-os-disk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces','cb-nic')]"
}
]
}
}
},
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "cb-vm/rdsdeployment",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', 'cb-vm')]",
"Microsoft.Compute/virtualMachines/gw-vm/extensions/gateway",
"rdsh-vm-loop"
],
"properties": {
"autoUpgradeMinorVersion": true,
"protectedSettings": {
"Items": {
"adminPassword": "[parameters('adminPassword')]"
}
},
"publisher": "Microsoft.Powershell",
"settings": {
"modulesUrl": "[concat(variables('assetLocation'),'/Configuration.zip')]",
"configurationFunction": "Configuration.ps1\\RDSDeployment",
"Properties": {
"adminCreds": {
"UserName": "[parameters('adminUsername')]",
"Password": "PrivateSettingsRef:adminPassword"
},
"connectionBroker": "[concat('broker.',parameters('adDomainName'))]",
"domainName": "[parameters('adDomainName')]",
"externalfqdn": "[reference(parameters('gwpublicIPAddressName')).dnsSettings.fqdn]",
"numberOfRdshInstances": "[parameters('numberOfRdshInstances')]",
"sessionHostNamingPrefix": "rdsh-",
"webAccessServer": "[concat('gateway.',parameters('adDomainName'))]"
}
},
"type": "DSC",
"typeHandlerVersion": "2.75"
}
}
]
}

Просмотреть файл

@ -0,0 +1,12 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"gwdnsLabelPrefix": {
"value": "GEN-UNIQUE"
},
"adminPassword": {
"value": "GEN-PASSWORD"
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"itemDisplayName": "Basic RDS farm deployment",
"description": "This template creates a basic RDS farm deployment",
"summary": "Creates and deploys a fully functional RDS farm",
"githubUsername": "MahendraAgrawal",
"dateUpdated": "2017-08-05"
}

Просмотреть файл

@ -0,0 +1,64 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualNetworkName": {
"type": "string",
"metadata": {
"description": "The name of the Virtual Network to Create"
}
},
"virtualNetworkAddressRange": {
"type": "string",
"metadata": {
"description": "The address range of the new VNET in CIDR format"
},
"defaultValue": "10.0.0.0/16"
},
"subnetName": {
"type": "string",
"metadata": {
"description": "The name of the subnet created in the new VNET"
}
},
"subnetRange": {
"type": "string",
"metadata": {
"description": "The address range of the subnet created in the new VNET"
},
"defaultValue": "10.0.0.0/24"
},
"dnsServerAddress": {
"type": "array",
"metadata": {
"description": "The DNS address(es) of the DNS Server(s) used by the VNET"
}
}
},
"resources": [
{
"apiVersion": "2015-06-15",
"name": "[parameters('virtualNetworkName')]",
"type": "Microsoft.Network/virtualNetworks",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('virtualNetworkAddressRange')]"
]
},
"dhcpOptions": {
"dnsServers": "[parameters('dnsServerAddress')]"
},
"subnets": [
{
"name": "[parameters('subnetName')]",
"properties": {
"addressPrefix": "[parameters('subnetRange')]"
}
}
]
}
}
]
}

Просмотреть файл

@ -0,0 +1,77 @@
# Configure certificates for RDS deployment
Click the button below to deploy:
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmmarch%2Fazure-quickstart-templates%2Fcerts-template%2Frds-update-certificate%2Fazuredeploy.json" target="_blank">
<img src="http://azuredeploy.net/deploybutton.png"/>
</a>
<a href="http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2Fmmarch%2Fazure-quickstart-templates%2Fcerts-template%2Frds-update-certificate%2Fazuredeploy.json" target="_blank">
<img src="http://armviz.io/visualizebutton.png"/>
</a>
<br><br>
This Template allows you configure certificates in an RDS deployment.
Remote Desktop Services require certificaties for
server authentication, single sign-on (SSO), and to secure RDP connections.
For a good overview of certificates use in RDS see
[Configuring RDS 2012 Certificates and SSO](https://ryanmangansitblog.com/2013/03/10/configuring-rds-2012-certificates-and-sso/) and
[How to Create a (Mostly) Seamless Logon Experience For Your Remote Desktop Services Environment](http://www.rdsgurus.com/windows-2012-r2-how-to-create-a-mostly-seamless-logon-experience-for-your-remote-desktop-services-environment/) by RDS MVP Toby Phipps.
The Template makes use of a single SSL certificate. The certificate's Subject Name must match external DNS name of RD Gateway server in the deployment.
The certificate with the private key (in .PFX format) must be stored in Azure Key Vault.
For information on managing certificates with Azure Key Vault see: [Get started with Azure Key Vault certificates](https://blogs.technet.microsoft.com/kv/2016/09/26/get-started-with-azure-key-vault-certificates/) and
[Manage certificates via Azure Key Vault](https://blogs.technet.microsoft.com/kv/2016/09/26/manage-certificates-via-azure-key-vault/).
## Pre-Requisites
0. Template is intended to run against an existing RDS deployment. The deployment can be created using one of RDS QuickStart templates
([Basic RDS Deployment Template](https://github.com/Azure/azure-quickstart-templates/tree/master/rds-deployment), or [RDS Deployment using existing VNET and AD](https://github.com/Azure/azure-quickstart-templates/tree/master/rds-deployment-existing-ad), etc.).
1. A certificate with the private key needs to be created (or acquired from CA) and imported to Azure Key Vault in tenant's subscription
(see [Get started with Azure Key Vault](https://azure.microsoft.com/en-us/documentation/articles/key-vault-get-started)).
Certificate's Subject Name should match external DNS name of the RDS Gateway server.
For example, to import an existing certificate stored as a .pfx file on your local hard drive run the following PowerShell:
```PowerShell
$vaultName = "myVault"
$certNameInVault = "certificate" # cert name in vault, has to be '^[0-9a-zA-Z-]+$' pattern (digits, letters or dashes only, no spaces)
$pfxFilePath = "c:\certificate.pfx"
$password = "B@kedPotat0" # password that was used to secure the pfx file at the time of export
Import-AzureKeyVaultCertificate -vaultname $vaultName -name $certNameInVault -filepath $pfxFilePath -password ($password | convertto-securestring -asplaintext -force)
```
Mark down 1) key vault name, and 2) certificate name in vault from this step - these will need to be supplied as input parameters to the Template.
2. A Service Principal account needs to be created with permissions to access certificates in the Key Vault
(see [Use Azure PowerShell to create a service principal to access resources](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authenticate-service-principal/)).
Sample powershell (alternatively you see Scripts\New-ServicePrincipal.ps1):
```PowerShell
$appPassword = "R@bberDuck"
$uri = "https://www.contoso.com/script" # a valid formatted URL, not validated for single-tenant deployments
$vaultName = "myVault" # same key vault name as in step #1 above
$app = New-AzureRmADApplication -DisplayName "script" -HomePage $uri -IdentifierUris $uri -password $appPassword
$sp = New-AzureRmADServicePrincipal -ApplicationId $app.ApplicationId
Set-AzureRmKeyVaultAccessPolicy -vaultname $vaultName -serviceprincipalname $sp.ApplicationId -permissionstosecrets get
```
Note: Certificates stored in Key Vault as secrets with content type 'application/x-pkcs12', this is why
`Set-AzureRmKeyVaultAccessPolivy` cmdlet grants `-PremissionsToSecrets` (rather than `-PermissionsToCertificates`).
You will need 1) application id (`$app.ApplicationId`), and 2) the password from above step supplied as input parameters to the Template.
You will also need your tenant Id. To get tenant Id run the following powershell:
```PowerShell
$tenantId = (Get-AzureRmSubscription).TenantId | select -Unique
```
## Running the Template
Template applies same certificate to all 4 roles in the deployment: `{ RDGateway | RDWebAccess | RDRedirector | RDPublishing }`.
Template performs the following steps:
+ downloads certificate from the key vault using Service Principal credentials;
+ invokes [Set-RDCertificate](https://technet.microsoft.com/en-us/library/jj215464.aspx) cmdlet to apply the certificate for each of the roles;
+ calls [Set-RDClientAccessName](https://technet.microsoft.com/en-us/library/jj215484.aspx) to update Client Access Name on RD Connection Broker to match the certificate.

Просмотреть файл

@ -0,0 +1,30 @@
[cmdletbinding()]
param(
[string]$appName = "rds-update-certificate-script",
# has to be a valid format URI; URI's not validated for single-tenant application
[string]$uri = "https://login.microsoft.com/rds-update-certificate-script",
[parameter(mandatory=$true)]
[string]$password,
[string]$vaultName
)
$app = New-AzureRmADApplication -DisplayName $appName -HomePage $uri -IdentifierUris $uri -password $pwd
$sp = New-AzureRmADServicePrincipal -ApplicationId $app.ApplicationId
if ($vaultName)
{
set-azurermkeyvaultaccesspolicy -vaultname $vaultName -serviceprincipalname $sp.ApplicationId -permissionstosecrets get
}
$tenantId = (get-azurermsubscription).TenantId | select -Unique
# outputs
#
"application id: $($app.ApplicationId)"
"tenant id: $tenantId"

Просмотреть файл

@ -0,0 +1,132 @@
[cmdletbinding()]
param(
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$appId,
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$appPassword,
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$tenantId,
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$vaultName,
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$secretName,
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$adminUsername,
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$adminPassword,
[parameter(mandatory = $true)][ValidateNotNullOrEmpty()] [string]$adDomainName,
[Parameter(ValueFromRemainingArguments = $true)]
$extraParameters
)
function log
{
param([string]$message)
"`n`n$(get-date -f o) $message"
}
log "script running..."
whoami
# $PSBoundParameters
if ($extraParameters)
{
log "any extra parameters:"
$extraParameters
}
# requires WMF 5.0
# verify NuGet package
$nuget = get-packageprovider nuget
if (-not $nuget -or ($nuget.Version -lt 2.8.5.22))
{
log "installing nuget package..."
install-packageprovider -name NuGet -minimumversion 2.8.5.201 -force
}
# install AzureRM module
#
if (-not (get-module AzureRM))
{
log "installing AzureRm powershell module..."
install-module AzureRM -force
}
# log onto azure account
#
log "logging onto azure account with app id = $appId ..."
$creds = new-object System.Management.Automation.PSCredential ($appId, (convertto-securestring $appPassword -asplaintext -force))
login-azurermaccount -credential $creds -serviceprincipal -tenantid $tenantId -confirm:$false
# get the secret from key vault
#
log "getting secret '$secretName' from keyvault '$vaultName'..."
$secret = get-azurekeyvaultsecret -vaultname $vaultName -name $secretName
$certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$bytes = [System.Convert]::FromBase64String($secret.SecretValueText)
$certCollection.Import($bytes, $null, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
add-type -AssemblyName System.Web
$password = [System.Web.Security.Membership]::GeneratePassword(38,5)
$protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $password)
$pfxFilePath = join-path $env:TEMP "$([guid]::NewGuid()).pfx"
log "writing the cert as '$pfxFilePath'..."
[io.file]::WriteAllBytes($pfxFilePath, $protectedCertificateBytes)
# apply certificate
#
ipmo remotedesktop -DisableNameChecking
# impersonate as admin
#
log "impersonating as '$adminUsername'..."
$admincreds = New-Object System.Management.Automation.PSCredential (($adminUsername + "@" + $adDomainName), (ConvertTo-SecureString $adminPassword -AsPlainText -Force))
.\New-ImpersonateUser.ps1 -Credential $admincreds
whoami
# apply certificate
#
$roles = @("RDGateway", "RDWebAccess", "RDRedirector", "RDPublishing")
$roles | % `
{
log "applying certificate for role: $_..."
set-rdcertificate -role $_ -importpath $pfxFilePath -password (convertto-securestring $password -asplaintext -force) -force
}
log "remove impersonation..."
Remove-ImpersonateUser
whoami
# set client access name
#
$gatewayConfig = get-rddeploymentgatewayconfiguration
if ($gatewayConfig -and $gatewayConfig.GatewayExternalFqdn)
{
$externalFqdn = $gatewayConfig.GatewayExternalFqdn
$externalDomainSuffix = $externalFqdn.substring($externalFqdn.IndexOf('.') + 1)
$clientAccessName = $env:COMPUTERNAME + '.' + $externalDomainSuffix
log "setting client access name to '$clientAccessName'..."
.\Set-RDPublishedName.ps1 -ClientAccessName $clientAccessName
}
# clean up
#
if (test-path($pfxFilePath))
{
log "running cleanup..."
remove-item $pfxFilePath
}
log "done."

Просмотреть файл

@ -0,0 +1,124 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vaultName": {
"type": "string",
"metadata": {
"description": "Azure Key Vault name where the certificate is stored."
}
},
"certificateName": {
"type": "string",
"metadata": {
"description": "Name of the certificate in the Azure Key Vault."
}
},
"applicationId": {
"type": "string",
"metadata": {
"description": "AD application Id used to access the certificate."
}
},
"applicationPassword": {
"type": "securestring",
"metadata": {
"description": "AD application password."
}
},
"tenantId": {
"type": "string",
"metadata": {
"description": "Tenant Id for whom the Secure Principal account was created."
}
},
"brokerVmName": {
"type": "string",
"metadata": {
"description": "Name of the RD Connection Broker VM resource in the deployment (the configure certificates script is executed on this VM)."
},
"defaultValue": "cb-vm"
},
"existingDomainName": {
"type": "string",
"metadata": {
"description": "The FQDN of the AD domain"
}
},
"existingAdminUsername": {
"type": "string",
"metadata": {
"description": "Name of the domain account with administrative priviledges in the RDS deployment"
}
},
"existingAdminPassword": {
"type": "securestring",
"metadata": {
"description": "The password for the administrator account of the new VM and the domain"
}
},
"_artifactsLocation": {
"type": "string",
"metadata": {
"description": "The base URI where artifacts required by this template are located. When the template is deployed using the accompanying scripts, a private location in the subscription will be used and this value will be automatically generated."
},
"defaultValue": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-update-certificate"
},
"_artifactsLocationSasToken": {
"type": "securestring",
"metadata": {
"description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated."
},
"defaultValue": ""
}
},
"variables": {
"p": {
"appid": "[concat(' -appId ', parameters('applicationId'))]",
"apppassword": "[concat(' -appPassword ', parameters('applicationPassword'))]",
"tenantid": "[concat(' -tenantId ', parameters('tenantId'))]",
"vault": "[concat(' -vaultName ', parameters('vaultName'))]",
"secret": "[concat(' -secretName ', parameters('certificateName'))]",
"adminUsername": "[concat(' -adminUsername ', parameters('existingAdminUsername'))]",
"adminPassword": "[concat(' -adminPassword ', parameters('existingAdminPassword'))]",
"adDomainName": "[concat(' -adDomainName ', parameters('existingDomainName'))]"
},
"scriptParameters": "[concat(variables('p').appid, variables('p').apppassword, variables('p').tenantid, variables('p').vault, variables('p').secret, variables('p').adminUsername, variables('p').adminPassword, variables('p').adDomainName)]",
"scriptFolder": "Scripts",
"scriptFileName": "Script.ps1",
"impersonateScript": "https://gallery.technet.microsoft.com/scriptcenter/Impersonate-a-User-9bfeff82/file/127189/1/New-ImpersonateUser.ps1",
"setPublishedNameScript": "https://gallery.technet.microsoft.com/Change-published-FQDN-for-2a029b80/file/103829/2/Set-RDPublishedName.ps1"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('brokerVmName'),'/customscript')]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "script"
},
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[variables('impersonateScript')]",
"[variables('setPublishedNameScript')]",
"[concat(parameters('_artifactsLocation'), '/', variables('scriptFolder'), '/', variables('scriptFileName'), parameters('_artifactsLocationSasToken'))]"
]
},
"protectedSettings": {
"commandToExecute": "[concat( 'powershell -noninteractive -executionpolicy bypass -file ', variables('scriptFileName'), variables('scriptParameters'), ' >> script.log 2>&1' )]"
}
}
}
],
"outputs": {
}
}

Просмотреть файл

@ -0,0 +1,33 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vaultName": {
"value": "myVault"
},
"certificateName": {
"value": "certificate"
},
"applicationId": {
"value": "GEN-UNIQUE"
},
"applicationPassword": {
"value": "GEN-PASSWORD"
},
"tenantId": {
"value": "GEN-UNIQUE"
},
"brokerVmName": {
"value": "cb-vm"
},
"existingDomainName": {
"value": "mydomain.local"
},
"existingAdminUsername": {
"value": "GEN-USER"
},
"existingAdminPassword": {
"value": "GEN-PASSWORD"
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"itemDisplayName": "Update RDS certificates template",
"description": "This template configures certificates in RDS deployment",
"summary": "Imports a PFX certificate from Azure Key Vault and configures RDS roles to use the certificate",
"githubUsername": "mmarch",
"dateUpdated": "2016-12-05"
}

Двоичные данные
rds-update-rdsh-collection/DSC/Configuration.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,23 @@
# Update Remote Desktop Sesson Collection to new template image
This template updates RDSH servers in existing session host collection with new updated template image. The URI for the image is provided as a template parameter.
This template deploys the following resources:
+ `<rdshNumberOfInstances`> new virtual machines as RDSH servers
Template does the following:
+ creates new RDSH instances from given template image and adds them to collection;
+ puts old RDSH servers in Drain mode to prevent new user connections;
+ notifies any logged on RD users that their sessions will be soon terminated due to collection maintenance;
+ logs off existing users from old RDSH instances after given timeout (`<userLogoffTimeoutInMinutes>` parameter).
Note: Template does **not** delete or deallocate old RDSH instances, so you may still incur compute charges. These virtual machine instances may need to be deleted manually.
Click the button below to deploy:
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmmarch%2Fazure-quickstart-templates%2Fmaster%2Frds-update-rdsh-collection%2Fazuredeploy.json" target="_blank">
<img src="http://azuredeploy.net/deploybutton.png"/>
</a>
<a href="http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2Fmmarch%2Fazure-quickstart-templates%2Fmaster%2Frds-update-rdsh-collection%2Fazuredeploy.json" target="_blank">
<img src="http://armviz.io/visualizebutton.png"/>
</a>

Просмотреть файл

@ -0,0 +1,237 @@
[cmdletbinding()]
param(
[parameter(mandatory = $true)]
[string]$domain,
[parameter(mandatory = $true)]
[string]$username,
[parameter(mandatory = $true)]
[string]$password,
[parameter(mandatory = $true)]
[string]$collection,
[parameter(mandatory = $true)]
[string]$iteration,
[parameter(mandatory = $true)]
[int]$nServers,
[parameter(mandatory = $true)]
[int]$nTimeoutMinutes,
[Parameter(ValueFromRemainingArguments = $true)]
$extraParameters
)
$title = "System Maintenance"
$message = "Please save your work. You will be logged off in $nTimeoutInMinutes minute(s)."
function log
{
param([string]$message)
"`n`n$(get-date -f o) $message"
}
function add-server
{
param(
[parameter(mandatory=$true)]
[string]$server
)
$cs = gwmi win32_computersystem; $broker = "$($cs.dnshostname).$($cs.domain)"
log "adding server $server to the deployment..."
add-rdserver $server -role rds-rd-server -ev e
if ($e -like '*deployment*not present*')
{
log "trying to create rds deployment..."
new-rdsessiondeployment -connectionbroker $broker -sessionhost $_ -ev e
if ($e -like "*$server*has reboots pending*")
{
log "attempting to reboot $server..."
restart-computer $server -force -wait
log "attempting to create deployment with $server one more time..."
new-rdsessiondeployment -connectionbroker $broker -sessionhost $_ -ea stop
}
elseif ($e)
{
throw
}
log "create deployment - success."
}
elseif ($e -like "*$server*has reboots pending*")
{
log "attempting to reboot $server..."
restart-computer $server -force -wait
log "attempting to add $server to deployment again after reboot..."
add-rdserver $server -role rds-rd-server -ea stop
}
elseif ($e)
{
throw
}
log "successfully added '$server' to the deployment."
}
log "script running..."
whoami
# $PSBoundParameters
if ($extraParameters)
{
log "any extra parameters:"
$extraParameters
}
log "attempting impersonate as $domain\$username..."
.\New-ImpersonateUser.ps1 -Username $username -Domain $domain -Password $password
try
{
ipmo remotedesktop -DisableNameChecking # 4>$null
# $domain = (gwmi win32_computersystem).Domain
$newServers = 0..$($nServers - 1) | % { "rdsh-$_$iteration.$domain" }
log "list of new servers:"
$newServers | % { " $($_.tolower())" }
# 1. add new servers to the deployment
#
log "current list of servers in the rds deployment:"
$existingServers = (get-rdserver).Server
$existingServers | % { " $($_.tolower())" }
$newServers | ? { -not ($_ -in $existingServers) } | % { add-server $_ }
# 2. add new servers to the rdsh collection
#
log "current list of rdsh servers in collection '$($collection)':"
$existingServers = (get-rdsessionhost -CollectionName $collection).SessionHost
if ($existingServers)
{
$existingServers | % { " $($_.tolower())" }
}
else
{
" --- no servers in the collection yet ----"
}
$serversToAdd = $newServers | ? { -not ($_ -in $existingServers) }
if ($serversToAdd)
{
log "adding new servers $($serversToAdd -join '; ') to session host collection '$collection'..."
add-rdsessionhost -collectionname $collection -sessionhost $serversToAdd -ea stop
}
# 3. put old servers in drain mode
#
$serversToRemove = $existingServers | ? { -not ($_ -in $newServers) }
if ($serversToRemove)
{
$serversToRemove | % `
{
log "putting server $_ in drain mode..."
set-rdsessionhost -sessionhost $_ -newconnectionallowed No
}
}
# 4. notify users they are going to be logged off in next <n> minutes
#
log "querying for user sessions in collection '$collection'..."
$sessions = get-rdusersession -CollectionName $collection
log "found total $($sessions.count) user sessions,"
$sessionsToLogoff = $sessions | ? { -not( $_.HostServer -in $newServers ) }
log "out of those $($sessionsToLogoff.count) sessions on the servers that are to be removed..."
if ($sessionsToLogoff)
{
$sessionsToLogoff| % `
{
log "sending message to user $($_.UserName) at host $($_.HostServer)..."
send-rdusermessage -hostserver $_.HostServer -unifiedsessionid $_.UnifiedSessionId -messagetitle $title -messagebody $message
}
}
# 5. log users off
#
if ($sessionsToLogoff)
{
log "waiting $nTimeoutMinutes munites before logging users off..."
start-sleep -s ($nTimeoutMinutes * 60)
log "querying for user sessions again..."
$sessions = get-rdusersession -CollectionName $collection
log "found total $($sessions.count) user sessions at this time,"
$sessionsToLogoff = $sessions | ? { -not( $_.HostServer -in $newServers ) }
log "out of those, $($sessionsToLogoff.count) sessions to be logged off..."
if ($sessionsToLogoff)
{
$sessionsToLogoff | % `
{
log "logging off user $($_.UserName) from host $($_.HostServer)..."
invoke-rduserlogoff -hostserver $_.HostServer -unifiedsessionid $_.SessionId -force
}
}
}
# 6. remove old servers from deployment
#
if ($serversToRemove)
{
log "removing servers $($serversToRemove -join '; ') from session host collection '$collection'..."
remove-rdsessionhost -sessionhost $serversToRemove -force
$serversToRemove | % `
{
log "removing server $_ from the deployment..."
remove-rdserver $_ -role rds-rd-server -force
}
log "shutting down servers $($serversToRemove -join '; ')..."
$creds = new-object System.Management.Automation.PSCredential ("$domain\$username", (convertto-securestring $password -asplaintext -force))
stop-computer -computer $serversToRemove -credential $creds -force
}
else
{
log "nothing to do."
}
}
catch
{
log "ERROR: caught exception"
throw
}
finally
{
log "remove impersonation..."
Remove-ImpersonateUser
}
log "done. success."

Просмотреть файл

@ -0,0 +1,264 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"existingRdshCollectionName": {
"type": "string",
"defaultValue": "Desktop Collection",
"metadata": {
"description": "Name of the RDSH collection to update"
}
},
"rdshTemplateImageUri": {
"type": "string",
"metadata": {
"description": "URI for the template VHD to use for RDSH instances. For example, https://rdsstorage.blob.core.windows.net/vhds/MyWindowServerOSImage.vhd"
}
},
"rdshUpdateIteration": {
"type": "string",
"metadata": {
"description": "A unique designator representing update iteration; newly created RDSH instances will have their names in the form: 'rdsh-&lt;index&gt;&lt;iteration&gt;"
}
},
"rdshNumberOfInstances": {
"type": "int",
"defaultValue": 2,
"metadata": {
"description": "Number of RD Session Hosts"
}
},
"rdshVmSize": {
"type": "string",
"metadata": {
"description": "The size of the RDSH virtual machines"
},
"defaultValue": "Standard_A2"
},
"userLogoffTimeoutInMinutes": {
"type": "int",
"defaultValue": 60,
"metadata": {
"description": "Timeout before forced user logoff from old RDSH instances"
}
},
"existingDomainName": {
"type": "string",
"metadata": {
"description": "Domain name of the exisiting RDS deployment"
}
},
"existingAdminUsername": {
"type": "string",
"metadata": {
"description": "The name of administrator in the existing RDS deployment"
}
},
"existingAdminPassword": {
"type": "securestring",
"metadata": {
"description": "Domain administrator password"
}
},
"existingVnetName": {
"type": "string",
"defaultValue": "vnet",
"metadata": {
"description": "VNET name"
}
},
"existingSubnetName": {
"type": "string",
"defaultValue": "Subnet",
"metadata": {
"description": "Subnet name"
}
},
"availabilitySet": {
"type": "string",
"defaultValue": "rdsh-availabilityset",
"metadata": {
"description": "Availability set for new RDSH instances"
}
},
"_artifactsLocation": {
"type": "string",
"metadata": {
"description": "The base URI where artifacts required by this template are located. When the template is deployed using the accompanying scripts, a private location in the subscription will be used and this value will be automatically generated."
},
"defaultValue": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/rds-update-rdsh-collection/"
},
"_artifactsLocationSasToken": {
"type": "securestring",
"metadata": {
"description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated."
},
"defaultValue": ""
}
},
"variables": {
"iteration": "[toLower(parameters('rdshUpdateIteration'))]",
"storageAccountName": "[split( split( parameters('rdshTemplateImageUri'), '/')[2], '.' )[0]]",
"impersonateScript": "https://gallery.technet.microsoft.com/scriptcenter/Impersonate-a-User-9bfeff82/file/127189/1/New-ImpersonateUser.ps1",
"p": {
"domain": "[concat(' -domain ', parameters('existingDomainName'))]",
"user": "[concat(' -username ', parameters('existingAdminUsername'))]",
"pwd": "[concat(' -password ', parameters('existingAdminPassword'))]",
"collection": "[concat(' -collection \"', parameters('existingRdshCollectionName'), '\"')]",
"iteration": "[concat(' -iteration ', toLower(parameters('rdshUpdateIteration')))]",
"servers": "[concat(' -nServers ', parameters('rdshNumberOfInstances'))]",
"timeout": "[concat(' -nTimeoutMinutes ', parameters('userLogoffTimeoutInMinutes'))]"
},
"scriptParameters": "[concat(variables('p').domain, variables('p').user, variables('p').pwd, variables('p').collection, variables('p').iteration, variables('p').servers, variables('p').timeout)]",
"scriptFolder": "Scripts",
"scriptFileName": "Script.ps1"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat('rdsh-', copyindex(),variables('iteration'), '-nic')]",
"location": "[resourceGroup().location]",
"copy": {
"name": "rdsh-nic-loop",
"count": "[parameters('rdshNumberOfInstances')]"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('existingVnetName'), parameters('existingSubnetName'))]"
}
}
}
]
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/availabilitySets",
"name": "[parameters('availabilitySet')]",
"location": "[resourceGroup().location]"
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat('rdsh-', copyindex(),variables('iteration'))]",
"location": "[resourceGroup().location]",
"copy": {
"name": "rdsh-vm-loop",
"count": "[parameters('rdshNumberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', 'rdsh-', copyindex(),variables('iteration'), '-nic')]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('rdshVmSize')]"
},
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', parameters('availabilitySet'))]"
},
"osProfile": {
"computerName": "[concat('rdsh-', copyindex(),variables('iteration'))]",
"adminUsername": "[parameters('existingAdminUsername')]",
"adminPassword": "[parameters('existingAdminPassword')]"
},
"storageProfile": {
"osDisk": {
"name": "[concat('rdsh-', copyindex(),variables('iteration'),'-osDisk')]",
"osType": "Windows",
"caching": "ReadWrite",
"createOption": "FromImage",
"image": {
"uri": "[parameters('rdshTemplateImageUri')]"
},
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), '2016-01-01').primaryEndpoints.blob, 'vhds/rdsh-', copyindex(), variables('iteration'), '-osdisk.vhd')]"
}
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat('rdsh-', copyindex(),variables('iteration'), '-nic'))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": "true",
"storageUri": "[reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), '2016-01-01').primaryEndpoints.blob]"
}
}
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat('rdsh-',copyindex(),variables('iteration'),'/sessionhost')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat('rdsh-', copyindex(),variables('iteration')))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.75",
"autoUpgradeMinorVersion": true,
"settings": {
"ModulesUrl": "[concat(parameters('_artifactsLocation'),'/DSC/Configuration.zip', parameters('_artifactsLocationSasToken'))]",
"ConfigurationFunction": "Configuration.ps1\\SessionHost",
"Properties": {
"DomainName": "[parameters('existingDomainName')]",
"AdminCreds": {
"UserName": "[parameters('existingAdminUsername')]",
"Password": "PrivateSettingsRef:AdminPassword"
}
}
},
"protectedSettings": {
"Items": {
"AdminPassword": "[parameters('existingAdminPassword')]"
}
}
}
}
]
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "cb-vm/customscript",
"location": "[resourceGroup().location]",
"dependsOn": [
"rdsh-vm-loop"
],
"tags": {
"displayName": "script"
},
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[variables('impersonateScript')]",
"[concat(parameters('_artifactsLocation'), '/', variables('scriptFolder'), '/', variables('scriptFileName'), parameters('_artifactsLocationSasToken'))]"
]
},
"protectedSettings": {
"commandToExecute": "[concat( 'powershell -noninteractive -executionpolicy bypass -file ', variables('scriptFileName'), variables('scriptParameters'), ' >> script.log 2>&1' )]"
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,33 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"existingDomainName": {
"value": "mydomain.local"
},
"existingAdminUsername": {
"value": "GEN-USER"
},
"existingAdminPassword": {
"value": "GEN-PASSWORD"
},
"rdshTemplateImageUri": {
"value": "https://rdsstorage.blob.core.windows.net/vhds/MyWindowServerOSImage.vhd"
},
"rdshUpdateIteration": {
"value": "a"
},
"userLogoffTimeoutInMinutes": {
"value": 60
},
"existingVnetName": {
"value": "vnet"
},
"existingSubnetName": {
"value": "subnet"
},
"availabilitySet": {
"value": "rdsh-availabilityset"
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"itemDisplayName": "Update RDSH collection",
"description": "This template updates servers in an RD Session Host collection",
"summary": "Updates existing session collection with new template image",
"githubUsername": "mmarch",
"dateUpdated": "2016-09-02"
}