Guest User

Untitled

a guest
Jun 1st, 2018
674
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. DESCRIPTION   This script will create a configured Remote Desktop Session Farm.
  3. Author:         Julian Mooren | https://citrixguyblog.com
  4. Contributer:    Sander van Gelderen | https://www.van-gelderen.eu
  5. Creation Date:  12.05.17
  6. Change Date:    09.02.18
  7. #>
  8.  
  9.  
  10. #Requires -version 4.0
  11. #Requires -RunAsAdministrator
  12.  
  13. #Functions
  14. #http://www.leeholmes.com/blog/2009/11/20/testing-for-powershell-remoting-test-psremoting/
  15. function Test-PsRemoting {
  16.     param(
  17.         [Parameter(Mandatory = $true)]
  18.         $computername
  19.     )
  20.    
  21.     try
  22.     {
  23.         $errorActionPreference = "Stop"
  24.         $result = Invoke-Command -ComputerName $computername { 1 }
  25.     }
  26.     catch
  27.     {
  28.         Write-Verbose $_
  29.         return $false
  30.     }
  31.    
  32.     ## I've never seen this happen, but if you want to be
  33.     ## thorough....
  34.     if($result -ne 1)
  35.     {
  36.         Write-Verbose "Remoting to $computerName returned an unexpected result."
  37.         return $false
  38.     }
  39.    
  40.     $true  
  41. } # end Test-PsRemoting
  42.  
  43. function Test-SQLDatabase
  44. {
  45.     param(
  46.     [Parameter(Position=0, Mandatory=$True, ValueFromPipeline=$True)] [string] $Server,
  47.     [Parameter(Position=1, Mandatory=$True)] [string] $Database,
  48.     [Parameter(Position=2, Mandatory=$True, ParameterSetName="SQLAuth")] [string] $Username,
  49.     [Parameter(Position=3, Mandatory=$True, ParameterSetName="SQLAuth")] [string] $Password,
  50.     [Parameter(Position=2, Mandatory=$True, ParameterSetName="WindowsAuth")] [switch] $UseWindowsAuthentication
  51.     )
  52.  
  53.     # connect to the database, then immediatly close the connection. If an exception occurrs it indicates the conneciton was not successful.
  54.     process {
  55.         $dbConnection = New-Object System.Data.SqlClient.SqlConnection
  56.         if (!$UseWindowsAuthentication) {
  57.             $dbConnection.ConnectionString = "Data Source=$Server; uid=$Username; pwd=$Password; Database=$Database;Integrated Security=False"
  58.             $authentication = "SQL ($Username)"
  59.         }
  60.         else {
  61.             $dbConnection.ConnectionString = "Data Source=$Server; Database=$Database;Integrated Security=True;"
  62.             $authentication = "Windows ($env:USERNAME)"
  63.         }
  64.         try {
  65.             $connectionTime = measure-command {$dbConnection.Open()}
  66.             $Result = @{
  67.                 Connection = "Successful"
  68.                 ElapsedTime = $connectionTime.TotalSeconds
  69.                 Server = $Server
  70.                 Database = $Database
  71.                 User = $authentication}
  72.         }
  73.         # exceptions will be raised if the database connection failed.
  74.         catch {
  75.                 $Result = @{
  76.                 Connection = "Failed"
  77.                 ElapsedTime = $connectionTime.TotalSeconds
  78.                 Server = $Server
  79.                 Database = $Database
  80.                 User = $authentication}
  81.         }
  82.         Finally{
  83.             # close the database connection
  84.             $dbConnection.Close()
  85.             #return the results as an object
  86.             $outputObject = New-Object -Property $Result -TypeName psobject
  87.             write-output $outputObject
  88.         }
  89.     }
  90. }
  91.  
  92. # Thanks @xenappblog.com for the Transcript Log idea
  93. $configpath= "C:\rds\config.json"
  94. $StartDate = (Get-Date)
  95. $Vendor = "Microsoft"
  96. $Product = "Remote Desktop Farm"
  97. $Version = "2016"
  98. $LogPath = "${env:SystemRoot}" + "\Temp\$Vendor $Product $Version.log"
  99.  
  100. Start-Transcript $LogPath
  101.  
  102. #region "Check Prerequisites"
  103. Write-Verbose "Check Prerequisites" -Verbose
  104.  
  105. #check that we are running script on Domain Controller
  106. if (Get-WindowsFeature -Name AD-Domain-Services | Where-Object {$_.Installed -eq $False}) {
  107.     Write-Warning "You are not running script on Domain Controller. Abort."
  108.     Stop-Transcript
  109.     break
  110. } else { Write-Verbose "You are on Domain Controller - good." }
  111.  
  112. if (Get-WindowsFeature -Name RSAT-AD-Tools, RSAT-DNS-Server){
  113.    Write-Verbose "Needed PowerShell Modules available." -Verbose
  114. } else {    
  115.     Write-Verbose "Needed PowerShell Modules will be installed." -Verbose
  116.     Install-WindowsFeature RSAT-AD-Tools, RSAT-DNS-Server
  117.     Write-Verbose "Needed PowerShell Modules have been installed." -Verbose
  118. } #end if Get-WindowsFeature
  119.  
  120. if (Test-Path $configpath) {
  121.     Write-Verbose "JSON File was found." -Verbose
  122.     $config = Get-Content -Path $configpath -Raw | ConvertFrom-Json
  123.     Write-Verbose "JSON File was imported." -Verbose
  124. } else {
  125.     Write-Warning "Failed to find the JSON File."
  126.     Stop-Transcript
  127.     break
  128. } #end if Test-Path $configpath
  129.  
  130. if (Test-Path $config.CertPath) {
  131.     Write-Verbose "SSL Certificate was found." -Verbose
  132. } Else {
  133.     Write-Warning "Failed to find the SSL Certificate."
  134.     Stop-Transcript
  135.     break
  136. } # end if Test-Path $config.CertPath
  137.  
  138. #check if logged in user is Domain Admin
  139. $LocalUser = &whoami
  140. $AdminUsernames = Get-ADGroupMember -Identity 'Domain Admins' -Recursive | Select-Object -ExpandProperty SamAccountName
  141. $AdminUsers = $AdminUsernames | ForEach-Object {$config.DomainNetbios+"\"+$_}
  142. If ($AdminUsers.Contains($LocalUser) -eq $False) {
  143.     Write-Warning "Logged in user does not belong to Domain Admins -group!"
  144.     Stop-Transcript
  145.     break
  146. } else { Write-Verbose "$LocalUser is Domain Admin - excellent." }
  147.  
  148. #endregion "Check Prerequisites"
  149.  
  150. #region TEST
  151. if($config.HADeployment -like "Yes"){
  152.  
  153.     if(Test-PsRemoting -computername $config.RDSHost01, $config.RDSHost02, $config.ConnectionBroker01, $config.ConnectionBroker02, $config.WebAccessServer01, $config.WebAccessServer02, $config.RDGatewayServer01, $config.RDGatewayServer02, $config.FileServerCluster ){
  154.         Write-Verbose "PSRemoting is enabled on all Hosts." -Verbose
  155.     } Else {
  156.         Write-Warning "PSRemoting is not enabled on all Hosts." -Verbose
  157.         $PSRemoteHA = @("$($config.RDSHost01)","$($config.RDSHost02)","$($config.ConnectionBroker01)","$($config.ConnectionBroker02)","$($config.WebAccessServer01)","$($config.WebAccessServer02)","$($config.RDGatewayServer01)","$($config.RDGatewayServer02)")
  158.         foreach($TestHA in $PSRemoteHA){
  159.             $status = Test-PsRemoting -computername $TestHA; "$TestHA;$status"
  160.         }
  161.         Stop-Transcript
  162.         break
  163.     } #end if Test-PsRemoting
  164.  
  165.     # Test SQL connection and logging
  166.     $SQLConnection = Test-SQLDatabase -Server $config.SQLServer -Database $config.SQLDatabase -UseWindowsAuthentication
  167.  
  168.     If ($SQLConnection.Connection -eq "Successful") {
  169.         Write-Verbose "SQL connection successful, $config.SQLDatabase exists"
  170.     }
  171.     else {
  172.         Write-Warning "Cannot reach SQL Database ($config.SQLDatabase), exiting ..."
  173.         Stop-Transcript
  174.         break
  175.     } #end of SQL tests
  176.  
  177.     #Add AD groups
  178.     Import-Module Activedirectory
  179.     $NameRDSAccessGroup = $config.RDSAccessGroup.split('@')[0]
  180.     $NameGatewayAccessGroup = $config.GatewayAccessGroup.split('@')[0]
  181.     New-ADGroup -Name $NameRDSAccessGroup -DisplayName $NameRDSAccessGroup -GroupCategory Security -GroupScope Global
  182.     New-ADGroup -Name $NameGatewayAccessGroup -DisplayName $NameGatewayAccessGroup -GroupCategory Security -GroupScope Global
  183.  
  184.     try {Invoke-WebRequest -Uri "https://download.microsoft.com/download/8/7/2/872BCECA-C849-4B40-8EBE-21D48CDF1456/ENU/x64/sqlncli.msi"} catch {Write-Warning "Couldnt Download SQL Native Client, copy sqlncli.msi to your broker servers.";Stop-Transcript; break}    
  185.  
  186.     if(!($NameGatewayAccessGroup)){Write-Warning "AD group $NameGatewayAccessGroup does not exist.";Stop-Transcript; break}
  187.  
  188.     #enable SMB    
  189.     Invoke-Command -ComputerName $config.ConnectionBroker01 {
  190.         Get-NetFirewallRule -DisplayName "File and Printer Sharing (SMB-In)" | Enable-NetFirewallRule
  191.     }
  192.     if(Test-Path "\\$($config.ConnectionBroker01)\c$"){Write-Verbose "UNC path reachable"} else { Write-Warning "$($config.ConnectionBroker01) might have troubles";Stop-Transcript; break}
  193.  
  194.     Invoke-Command -ComputerName $config.ConnectionBroker02 {
  195.         Get-NetFirewallRule -DisplayName "File and Printer Sharing (SMB-In)" | Enable-NetFirewallRule
  196.     }
  197.     if(Test-Path "\\$($config.ConnectionBroker02)\c$"){Write-Verbose "UNC path reachable"} else { Write-Warning "$($config.ConnectionBroker02) might have troubles"}
  198.    
  199. }
  200.  
  201. #enable SMB on FileServerCluster
  202. Invoke-Command -ComputerName $config.FileServerCluster {
  203.     Get-NetFirewallRule -DisplayName "File and Printer Sharing (SMB-In)" | Enable-NetFirewallRule
  204. }
  205.  
  206. # create UserProfile folder & set permissions
  207. if(Test-Path "\\$($config.FileServerCluster)\c$") {
  208.     Write-Verbose "UNC path reachable"    
  209.     #invoke-command -computername DC2 -scriptblock {new-item -itemtype directory -path $args[0] -verbose -credentials $args[1]} -argumentlist $homeDir,$cred
  210.     Invoke-Command -ComputerName $config.FileServerCluster -ArgumentList $config.ProfilePath, $config.DomainNetbios, $config.AdminGroup {              
  211.         $ProfilePath = $args[0]
  212.         $DomainNetbios = $args[1]
  213.         $AdminGroup = $args[2]
  214.         New-Item -ItemType directory -Path $ProfilePath
  215.         New-SMBShare –Name "UserProfiles" –Path $ProfilePath –FullAccess "$DomainNetbios\$AdminGroup" -ReadAccess "Everyone"
  216.     }
  217. }
  218. else { Write-Warning "$($config.FileServerCluster) might have troubles. Could not reach Cee dollar";Stop-Transcript; break }
  219.  
  220. if(Test-Path "$($config.ProfileDiskPath)"){Write-Verbose "Profile path reachable"  -Verbose} else { Write-Warning "$($config.ProfileDiskPath) might have troubles"  -Verbose;Stop-Transcript; break}
  221.  
  222. if(!($NameRDSAccessGroup)){Write-Warning "AD group $NameRDSAccessGroup does not exist."  -Verbose;Stop-Transcript; break}
  223.  
  224. Read-Host "All Testing is done. Ready for the real stuff? -> Press enter to continue"
  225.  
  226. #endregion TEST
  227.  
  228. Write-Verbose "Starting Installation of $Vendor $Product $Version" -Verbose
  229.  
  230. # Import the RemoteDesktop Module
  231. Import-Module RemoteDesktop
  232.  
  233. ##### MultiDeployment Configuration Parameters #####
  234.  
  235. if($config.MultiDeployment -like "Yes"){
  236.  
  237.     # Create RDS deployment
  238.     New-RDSessionDeployment -ConnectionBroker $config.ConnectionBroker01 -WebAccessServer $config.WebAccessServer01 -SessionHost @($config.RDSHost01, $config.RDSHost02)
  239.     Write-Verbose "Created new RDS deployment" -Verbose
  240.  
  241.     # Create Desktop Collection
  242.     New-RDSessionCollection  -CollectionName $config.DesktopCollectionName -SessionHost @($config.RDSHost01, $config.RDSHost02)  -CollectionDescription $config.DesktopDiscription  -ConnectionBroker $config.ConnectionBroker01
  243.     Write-Verbose "Created new Desktop Collection"  -Verbose
  244.  
  245.     #Install Gateway
  246.     Add-WindowsFeature -Name RDS-Gateway -IncludeManagementTools -ComputerName $config.RDGatewayServer01
  247.     Write-Verbose "Installed RDS Gateway"  -Verbose
  248.  
  249.     #Join Gateway to Broker
  250.     Add-RDServer -Server $config.RDGatewayServer01 -Role "RDS-GATEWAY" -ConnectionBroker $config.ConnectionBroker01 -GatewayExternalFqdn $config.GatewayExternalFqdn
  251.     Write-Verbose "Joined RDS Gateway to Broker"  -Verbose
  252.    
  253.     # Configure GW Policies on RDGatewayServer01
  254.     Invoke-Command -ComputerName $config.RDGatewayServer01 -ArgumentList $config.GatewayAccessGroup, $config.RDBrokerDNSInternalName, $config.RDBrokerDNSInternalZone, $config.RDSHost01, $config.RDSHost02 -ScriptBlock {
  255.         $GatewayAccessGroup = $args[0]
  256.         $RDBrokerDNSInternalName = $args[1]
  257.         $RDBrokerDNSInternalZone = $args[2]
  258.         $RDSHost01 = $args[3]
  259.         $RDSHost02 = $args[4]
  260.         Import-Module RemoteDesktopServices
  261.         Remove-Item -Path "RDS:\GatewayServer\CAP\RDG_CAP_AllUsers" -Force -recurse
  262.         Remove-Item -Path "RDS:\GatewayServer\RAP\RDG_RDConnectionBrokers" -Force -recurse
  263.         Remove-Item -Path "RDS:\GatewayServer\RAP\RDG_AllDomainComputers" -Force -recurse
  264.         Remove-Item -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDG_RDCBComputers" -Force -recurse
  265.         New-Item -Path "RDS:\GatewayServer\GatewayManagedComputerGroups" -Name "RDSFarm1" -Description "RDSFarm1" -Computers "$RDBrokerDNSInternalName.$RDBrokerDNSInternalZone" -ItemType "String"
  266.         New-Item -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDSFarm1\Computers" -Name $RDSHost01 -ItemType "String"
  267.         New-Item -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDSFarm1\Computers" -Name $RDSHost02 -ItemType "String"
  268.  
  269.         New-Item -Path "RDS:\GatewayServer\RAP" -Name "RDG_RAP_RDSFarm1" -UserGroups $GatewayAccessGroup -ComputerGroupType 0 -ComputerGroup "RDSFarm1"
  270.         New-Item -Path "RDS:\GatewayServer\CAP" -Name "RDG_CAP_RDSFarm1" -UserGroups $GatewayAccessGroup -AuthMethod 1
  271.  
  272.     }
  273.     Write-Verbose "Configured CAP & RAP Policies on: $($config.RDGatewayServer01)"  -Verbose
  274.  
  275.     read-host "Configuring CAP & RAP on $($config.RDGatewayServer01) error? Re-run this part of the script before continue"
  276.  
  277.     # Create WebAccess DNS-Record
  278.     Import-Module DNSServer
  279.     $IPWebAccess01 = [System.Net.Dns]::GetHostAddresses("$($config.WebAccessServer01)")[0].IPAddressToString
  280.     Add-DnsServerResourceRecordA -ComputerName $config.DomainController -Name $config.RDWebAccessDNSInternalName -ZoneName $config.RDWebAccessDNSInternalZone -AllowUpdateAny -IPv4Address $IPWebAccess01
  281.     Write-Verbose "Configured WebAccess DNS-Record"  -Verbose
  282.  
  283.     # Redirect to RDWeb (IIS)
  284.     Invoke-Command -ComputerName $config.WebAccessServer01 -ArgumentList $config.RDWebAccessDNSInternalName, $config.RDWebAccessDNSInternalZone  -ScriptBlock {
  285.         $RDWebAccessDNSInternalName = $args[0]
  286.         $RDWebAccessDNSInternalZone = $args[1]
  287.         $siteName = "Default Web Site"
  288.         Import-Module webAdministration
  289.         Set-WebConfiguration system.webServer/httpRedirect "IIS:\sites\$siteName" -Value @{enabled="true";destination="https://$RDWebAccessDNSInternalName.$RDWebAccessDNSInternalZone/RDWeb";exactDestination="true";httpResponseStatus="Found"}
  290.     } #end Redirect to RDWeb
  291.     Write-Verbose "Configured RDWeb Redirect"  -Verbose
  292.  
  293. } #end if $config.MultiDeployment
  294.  
  295. #region Default Configuration Parameters
  296. ##### Default Configuration Parameters #####
  297.  
  298. # Set Access Group for RDS Farm
  299. Set-RDSessionCollectionConfiguration -CollectionName $config.DesktopCollectionName -UserGroup $config.RDSAccessGroup -ConnectionBroker $config.ConnectionBroker01
  300. Write-Verbose "Configured Access for $($config.RDSAccessGroup)"  -Verbose
  301.  
  302. # Set Profile Disk
  303. Set-RDSessionCollectionConfiguration -CollectionName $config.DesktopCollectionName -EnableUserProfileDisk -MaxUserProfileDiskSizeGB "20" -DiskPath $config.ProfileDiskPath -ConnectionBroker $config.ConnectionBroker01
  304. Write-Verbose "Configured ProfileDisk"  -Verbose
  305.  
  306. # RDS Licencing
  307. Add-RDServer -Server $config.LICserver1 -Role "RDS-LICENSING" -ConnectionBroker $config.ConnectionBroker01
  308. Add-RDServer -Server $config.LICserver2 -Role "RDS-LICENSING" -ConnectionBroker $config.ConnectionBroker02
  309. Write-Verbose "Installed RDS Licence Server: $($config.LICserver)"  -Verbose
  310. Set-RDLicenseConfiguration -LicenseServer $config.LICserver1, $config.LICserver2 -Mode $config.LICmode -ConnectionBroker $config.ConnectionBroker01 -Force
  311. Write-Verbose "Configured RDS Licening. $config.ConnectionBroker01 is primary License server!"  -Verbose
  312.  
  313. # Set Certificates
  314. $Password = ConvertTo-SecureString -String $config.CertPassword -AsPlainText -Force
  315. Set-RDCertificate -Role RDPublishing -ImportPath $config.CertPath  -Password $Password -ConnectionBroker $config.ConnectionBroker01 -Force
  316. Set-RDCertificate -Role RDRedirector -ImportPath $config.CertPath -Password $Password -ConnectionBroker $config.ConnectionBroker01 -Force
  317. Set-RDCertificate -Role RDWebAccess -ImportPath $config.CertPath -Password $Password -ConnectionBroker $config.ConnectionBroker01 -Force
  318. Set-RDCertificate -Role RDGateway -ImportPath $config.CertPath  -Password $Password -ConnectionBroker $config.ConnectionBroker01 -Force
  319. Write-Verbose "Configured SSL Certificates"  -Verbose
  320.  
  321. # Configure WebAccess (when RDBroker is available, no Gateway will be used)
  322. Set-RDDeploymentGatewayConfiguration -GatewayMode Custom -GatewayExternalFqdn $config.GatewayExternalFqdn -LogonMethod Password -UseCachedCredentials $True -BypassLocal $True -ConnectionBroker $config.ConnectionBroker01 -Force
  323. Write-Verbose "Configured Gateway Mapping"  -Verbose
  324.  
  325. # Create TXT WebFeed DNS Record - Create RemoteAccess connection via e-Mail address
  326. Add-DnsServerResourceRecord -ZoneName $config.RDWebAccessDNSInternalZone -Name "_msradc" -Txt -DescriptiveText "https://$($config.RDWebAccessDNSInternalName).$($config.RDWebAccessDNSInternalZone)/RDWeb/Feed"
  327. Write-Verbose "Created TXT WebFeed DNS Record"  -Verbose
  328.  
  329. # Create RDS Broker DNS-Record
  330. Import-Module DNSServer
  331. $IPBroker01 = [System.Net.Dns]::GetHostAddresses("$($config.ConnectionBroker01)")[0].IPAddressToString
  332. Add-DnsServerResourceRecordA -ComputerName $config.DomainController  -Name $config.RDBrokerDNSInternalName -ZoneName $config.RDBrokerDNSInternalZone -AllowUpdateAny -IPv4Address $IPBroker01
  333. Write-Verbose "Configured RDSBroker DNS-Record"  -Verbose
  334.  
  335. #Change RDPublishedName
  336. #https://gallery.technet.microsoft.com/Change-published-FQDN-for-2a029b80
  337. Invoke-WebRequest -Uri "https://gallery.technet.microsoft.com/Change-published-FQDN-for-2a029b80/file/103829/2/Set-RDPublishedName.ps1" -OutFile "c:\rds\Set-RDPublishedName.ps1"
  338. Copy-Item "c:\rds\Set-RDPublishedName.ps1" -Destination "\\$($config.ConnectionBroker01)\c$"
  339. Invoke-Command -ComputerName $config.ConnectionBroker01 -ArgumentList $config.RDBrokerDNSInternalName, $config.RDBrokerDNSInternalZone -ScriptBlock {
  340.     $RDBrokerDNSInternalName = $args[0]
  341.     $RDBrokerDNSInternalZone = $args[1]
  342.     Set-Location C:\
  343.     .\Set-RDPublishedName.ps1 -ClientAccessName "$RDBrokerDNSInternalName.$RDBrokerDNSInternalZone"
  344.     Remove-Item "C:\Set-RDPublishedName.ps1"
  345. }
  346. Write-Verbose "Configured RDPublisher Name"  -Verbose
  347. #endregion Default Configuration Parameters
  348.  
  349.  
  350. ##### HA Configuration Configuration Parameters #####
  351.  
  352. if($config.HADeployment -like "Yes"){
  353.  
  354.     #Create HA Broker Security Group for SQL Database Access
  355.     Import-Module ActiveDirectory
  356.     New-ADGroup  -Name "RDS_Connection_Brokers" -GroupCategory Security -GroupScope Global  -Server $config.DomainController
  357.     #wrong servers where added to the group (RDS), changed to brokers
  358.     Add-ADGroupMember -Identity "RDS_Connection_Brokers" -Members "$($config.ConnectionBroker01.Split(".")[0])$" -Server $config.DomainController
  359.     Add-ADGroupMember -Identity "RDS_Connection_Brokers" -Members "$($config.ConnectionBroker02.Split(".")[0])$" -Server $config.DomainController
  360.     Write-Verbose "Created RDSBroker Security Group in ActiveDirectory" -Verbose
  361.  
  362.     # Restart Broker Server (that Broker Security Group is being applied)
  363.     #alternative without server reboot
  364.     #klist -lh 0 -li 0x3e7 purge
  365.     #klist -lh 0 -li x3e7 purge
  366.  
  367.     Write-Verbose "$($config.ConnectionBroker01) will reboot"  -Verbose
  368.     Restart-Computer -ComputerName $config.ConnectionBroker01 -Wait -For PowerShell -Timeout 300 -Delay 2 -Force
  369.     Write-Verbose "$($config.ConnectionBroker01) online again"  -Verbose
  370.  
  371.     #Reboot ConnectionBroker02 (without Reboot, there can occur errors with the next commands)
  372.     Write-Verbose "$($config.ConnectionBroker02) will reboot"  -Verbose
  373.     Restart-Computer -ComputerName $config.ConnectionBroker02 -Wait -For PowerShell -Timeout 300 -Delay 2 -Force
  374.     Write-Verbose "$($config.ConnectionBroker02) online again"  -Verbose
  375.  
  376.     # Create HA RDS Broker DNS-Record
  377.     Import-Module DNSServer
  378.     $IPBroker02 = [System.Net.Dns]::GetHostAddresses("$($config.ConnectionBroker02)")[0].IPAddressToString
  379.     Add-DnsServerResourceRecordA -ComputerName $config.DomainController  -Name $config.RDBrokerDNSInternalName -ZoneName $config.RDBrokerDNSInternalZone -AllowUpdateAny -IPv4Address $IPBroker02
  380.     Write-Verbose "Configured RDSBroker DNS-Record"  -Verbose
  381.  
  382.     # Create HA WebAccess DNS-Record
  383.     Import-Module DNSServer
  384.     $IPWebAccess02 = [System.Net.Dns]::GetHostAddresses("$($config.WebAccessServer02)")[0].IPAddressToString
  385.     Add-DnsServerResourceRecordA -ComputerName $config.DomainController  -Name $config.RDWebAccessDNSInternalName -ZoneName $config.RDWebAccessDNSInternalZone -AllowUpdateAny -IPv4Address $IPWebAccess02
  386.     Write-Verbose "Configured WebAccess DNS-Record"  -Verbose
  387.  
  388.     # Download SQL Native Client
  389.     try {Invoke-WebRequest -Uri "https://download.microsoft.com/download/8/7/2/872BCECA-C849-4B40-8EBE-21D48CDF1456/ENU/x64/sqlncli.msi" -OutFile "c:\rds\sqlncli.msi"} catch {(Read-Host "Last change :-), copy sqlncli.msi to the brokers!. 'Press enter to continue'")}
  390.     if (Test-Path c:\rds\sqlncli.msi) {
  391.         Write-Verbose "Downloaded SQL Native Client" -Verbose
  392.     } Else {
  393.         Write-Warning "Couldnt Download SQL Native Client"
  394.         Stop-Transcript
  395.         break
  396.     } #end Test-Path c:\rds\sqlncli.msi
  397.  
  398.     #Install SQLNativeClient on ConnectionBroker01
  399.     Copy-Item "c:\rds\sqlncli.msi" -Destination "\\$($config.ConnectionBroker01)\c$"
  400.     Invoke-Command -ComputerName $config.ConnectionBroker01 -ArgumentList $config.ConnectionBroker01 -ScriptBlock {
  401.         $ConnectionBroker01 = $args[0]
  402.         $install = Start-Process "msiexec.exe" -ArgumentList "/i C:\sqlncli.msi", "/qn", "IACCEPTSQLNCLILICENSETERMS=YES", "/log C:\sql.log" -PassThru -Wait
  403.  
  404.         if ($install.ExitCode -ne 0) {
  405.             Write-Warning "SQL Client failed to install with $($install.ExitCode) on $ConnectionBroker01"
  406.             Stop-Transcript
  407.             break
  408.         } else {
  409.             Write-Verbose "SQL Client installed succesfull on $ConnectionBroker01" -Verbose
  410.         }
  411.         Remove-Item "C:\sqlncli.msi"
  412.     }
  413.  
  414.     #Install SQLNativeClient on ConnectionBroker02
  415.     Copy-Item "c:\rds\sqlncli.msi" -Destination "\\$($config.ConnectionBroker02)\c$"
  416.     Invoke-Command -ComputerName $config.ConnectionBroker02 -ArgumentList $config.ConnectionBroker02 -ScriptBlock {
  417.         $ConnectionBroker02 = $args[0]
  418.         $install = Start-Process "msiexec.exe" -ArgumentList "/i C:\sqlncli.msi", "/qn", "IACCEPTSQLNCLILICENSETERMS=YES", "/log C:\sql.log" -PassThru -Wait
  419.  
  420.         if ($install.ExitCode -ne 0) {
  421.             Write-Warning "SQL Client failed to install with $($install.ExitCode) on $ConnectionBroker02"
  422.             Stop-Transcript
  423.             break
  424.         } else {
  425.             Write-Verbose "SQL Client installed succesfull on $ConnectionBroker02" -Verbose
  426.         }
  427.         Remove-Item "C:\sqlncli.msi"
  428.     }
  429.  
  430.     #Configure RDSBrokerHighAvailability
  431.  
  432.     Invoke-Command -ComputerName $config.SQLServer -ArgumentList $config.SQLServer, $config.DomainNetbios -ScriptBlock {
  433.         $SQLserver = $args[0]
  434.         $NetBios = $args[1]
  435.  
  436.         [void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO')
  437.         $server = new-Object Microsoft.SqlServer.Management.Smo.Server("$SQLserver")
  438.         $SqlUser = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Login ($server,"$NetBios\RDS_Connection_Brokers")
  439.         $SqlUser.LoginType='WindowsUser'
  440.         $SqlUser.create()
  441.  
  442.         $SvrRole = $server.Roles | where {$_.Name -eq 'sysadmin'};
  443.         $SvrRole.AddMember("$NetBios\RDS_Connection_Brokers");
  444.     }
  445.  
  446.     #(Read-Host 'Please give the "RDS_Connection_Brokers" Security Group the right "sysadmin" to create the databases on the SQL Server. Press Enter when finished')
  447.  
  448.     Set-RDConnectionBrokerHighAvailability -ConnectionBroker $config.ConnectionBroker01`
  449.     -DatabaseConnectionString "DRIVER=SQL Server Native Client 11.0;SERVER=$($config.SQLServer);Trusted_Connection=Yes;APP=Remote Desktop Services Connection Broker;DATABASE=$($config.SQLDatabase)"`
  450.     -ClientAccessName "$($config.RDBrokerDNSInternalName).$($config.RDBrokerDNSInternalZone)"
  451.     #parameter DatabaseFilePath not needed.
  452.     #-DatabaseFilePath  $config.SQLFilePath
  453.     Write-Verbose "Configured RDSBroker High Availablilty"  -Verbose
  454.  
  455.    
  456.     #Join ConnectionBroker02
  457.     Invoke-Command -ComputerName $config.ConnectionBroker02 -ScriptBlock {
  458.         <#
  459.         Don't know why, but pre installing the RDS-Connection-Broker role prevents the error: The server BR2.rdsfarm.lab has to be same OS version as the active RD Connection Broker server BR1.rdsfarm.lab: Microsoft Windows Server 2016 Standard.
  460.         #>
  461.         Install-WindowsFeature RDS-Connection-Broker
  462.     }
  463.    
  464.     Add-RDServer -Server $config.ConnectionBroker02 -Role "RDS-CONNECTION-BROKER" -ConnectionBroker $config.ConnectionBroker01
  465.     Write-Verbose "Joined Broker Server: $($config.ConnectionBroker02)"  -Verbose
  466.  
  467.     #Reboot ConnectionBroker02 (without Reboot, there can occur errors with the next commands)
  468.     Write-Verbose "$($config.ConnectionBroker02) will reboot"  -Verbose
  469.     Restart-Computer -ComputerName $config.ConnectionBroker02 -Wait -For PowerShell -Timeout 300 -Delay 2 -Force
  470.     Write-Verbose "$($config.ConnectionBroker02) online again"  -Verbose
  471.  
  472.     read-host "If reboot of $($config.ConnectionBroker02) fails, do it manualy!"
  473.  
  474.     #Determine ActiveBroker
  475.     $primaryBroker = (Get-RDConnectionBrokerHighAvailability -ConnectionBroker $config.ConnectionBroker01).ActiveManagementServer
  476.  
  477.     #Join WebAccess02
  478.     Add-RDServer -Server $config.WebAccessServer02 -Role "RDS-WEB-ACCESS" -ConnectionBroker $primaryBroker
  479.     Write-Verbose "Joined WebAccess Server:  $($config.ConnectionBroker02)"  -Verbose
  480.  
  481.     # WebAccess02 - Redirect to RDWeb (IIS)
  482.     Invoke-Command -ComputerName $config.WebAccessServer02 -ArgumentList $config.RDWebAccessDNSInternalName, $config.RDWebAccessDNSInternalZone  -ScriptBlock {
  483.         $RDWebAccessDNSInternalName = $args[0]
  484.         $RDWebAccessDNSInternalZone = $args[1]
  485.         $siteName = "Default Web Site"
  486.         Import-Module webAdministration
  487.         Set-WebConfiguration system.webServer/httpRedirect "IIS:\sites\$siteName" -Value @{enabled="true";destination="https://$RDWebAccessDNSInternalName.$RDWebAccessDNSInternalZone/RDWeb";exactDestination="true";httpResponseStatus="Found"}
  488.     }
  489.     Write-Verbose "Configured RDWeb Redirect"  -Verbose
  490.  
  491.     # Create same Machine Key for RDWeb Services
  492.     # https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-rdweb-gateway-ha
  493.     # https://gallery.technet.microsoft.com/Get-and-Set-the-machineKeys-9a1e7b77
  494.     Invoke-WebRequest -Uri "https://gallery.technet.microsoft.com/Get-and-Set-the-machineKeys-9a1e7b77/file/122500/1/Configure-MachineKeys.ps1" -OutFile "c:\rds\Configure-MachineKeys.ps1"
  495.     if (Test-Path c:\rds\Configure-MachineKeys.ps1){
  496.         Write-Verbose "Downloaded Configure-MachineKeys Script" -Verbose
  497.         c:\rds\Configure-MachineKeys.ps1 -ComputerName $config.WebAccessServer01, $config.WebAccessServer02 -Mode Write
  498.         Write-Verbose "Configured same Machine Key for RDWeb Servers"
  499.     } Else {
  500.         Write-Warning "Couldnt download Configure-MachineKeys Script"
  501.         Stop-Transcript
  502.         break
  503.     }
  504.  
  505.     #Join RDGatewayServer02
  506.     Add-RDServer -Server $config.RDGatewayServer02 -Role "RDS-GATEWAY" -ConnectionBroker $primaryBroker -GatewayExternalFqdn $config.GatewayExternalFqdn
  507.     Write-Verbose "Joined Gateway Server:  $($config.ConnectionBroker02)"  -Verbose
  508.  
  509.     # Configure GW Policies on RDGatewayServer02
  510.     Invoke-Command -ComputerName $config.RDGatewayServer02 -ArgumentList $config.GatewayAccessGroup, $config.RDBrokerDNSInternalName, $config.RDBrokerDNSInternalZone, $config.RDSHost01, $config.RDSHost02, $config.RDGatewayServer01, $config.RDGatewayServer02 -ScriptBlock {
  511.         $GatewayAccessGroup = $args[0]
  512.         $RDBrokerDNSInternalName = $args[1]
  513.         $RDBrokerDNSInternalZone = $args[2]
  514.         $RDSHost01 = $args[3]
  515.         $RDSHost02 = $args[4]
  516.         $RDGatewayServer01 = $args[5]
  517.         $RDGatewayServer02 = $args[6]
  518.         Import-Module RemoteDesktopServices
  519.         Remove-Item -Path "RDS:\GatewayServer\CAP\RDG_CAP_AllUsers" -Force -recurse
  520.         Remove-Item -Path "RDS:\GatewayServer\RAP\RDG_RDConnectionBrokers" -Force -recurse
  521.         Remove-Item -Path "RDS:\GatewayServer\RAP\RDG_AllDomainComputers" -Force -recurse
  522.         Remove-Item -Path "RDS:\GatewayServer\RAP\RDG_HighAvailabilityBroker_DNS_RR" -Force -recurse
  523.         Remove-Item  -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDG_RDCBComputers"-Force -recurse
  524.         Remove-Item  -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDG_DNSRoundRobin"-Force -recurse
  525.         New-Item -Path "RDS:\GatewayServer\GatewayManagedComputerGroups" -Name "RDSFarm1" -Description "RDSFarm1" -Computers "$RDBrokerDNSInternalName.$RDBrokerDNSInternalZone" -ItemType "String"
  526.         New-Item -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDSFarm1\Computers" -Name $RDSHost01 -ItemType "String"
  527.         New-Item -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDSFarm1\Computers" -Name $RDSHost02 -ItemType "String"
  528.         New-Item -Path "RDS:\GatewayServer\RAP" -Name "RDG_RAP_RDSFarm1" -UserGroups $GatewayAccessGroup -ComputerGroupType 0 -ComputerGroup "RDSFarm1"
  529.         New-Item -Path "RDS:\GatewayServer\CAP" -Name "RDG_CAP_RDSFarm1" -UserGroups $GatewayAccessGroup -AuthMethod 1
  530.         New-Item -Path "RDS:\GatewayServer\GatewayFarm\Servers" -Name $RDGatewayServer01 -ItemType "String"
  531.         New-Item -Path "RDS:\GatewayServer\GatewayFarm\Servers" -Name $RDGatewayServer02 -ItemType "String"
  532.     } #end invoke GW Policies on RDGatewayServer02
  533.     Write-Verbose "Configured CAP & RAP Policies on: $($config.RDGatewayServer02)"  -Verbose
  534.  
  535.     #Cleanup Gateway Policies on RDGatewayServer01
  536.     Invoke-Command -ComputerName $config.RDGatewayServer01 -ScriptBlock {
  537.         Import-Module RemoteDesktopServices
  538.         Remove-Item -Path "RDS:\GatewayServer\RAP\RDG_HighAvailabilityBroker_DNS_RR" -Force -recurse
  539.         Remove-Item  -Path "RDS:\GatewayServer\GatewayManagedComputerGroups\RDG_DNSRoundRobin"-Force -recurse
  540.     } #ne invoke Cleanup Gateway Policies on RDGatewayServer01
  541.     Write-Verbose "Cleanup RAP Policy on: $($config.RDGatewayServer01)"  -Verbose
  542.  
  543.     #Create Gateway Farm on RDGatewayServer01
  544.     Invoke-Command -ComputerName $config.RDGatewayServer01 -ArgumentList $config.RDGatewayServer01, $config.RDGatewayServer02 -ScriptBlock {
  545.         $RDGatewayServer01 = $args[0]
  546.         $RDGatewayServer02 = $args[1]
  547.         Import-Module RemoteDesktopServices
  548.         New-Item -Path "RDS:\GatewayServer\GatewayFarm\Servers" -Name $RDGatewayServer01 -ItemType "String"
  549.         New-Item -Path "RDS:\GatewayServer\GatewayFarm\Servers" -Name $RDGatewayServer02 -ItemType "String"
  550.     } #end invoke Create Gateway Farm on RDGatewayServer01
  551.     Write-Verbose "Created Gateway Server Farm on: $($config.RDGatewayServer01)"  -Verbose
  552.  
  553.     #Set Certificates (need to be applied again, that ConnectioBroker02 is getting the certificates)
  554.     $Password = ConvertTo-SecureString -String $config.CertPassword -AsPlainText -Force
  555.     Set-RDCertificate -Role RDPublishing -ImportPath $config.CertPath  -Password $Password -ConnectionBroker $primaryBroker -Force
  556.     Set-RDCertificate -Role RDRedirector -ImportPath $config.CertPath -Password $Password -ConnectionBroker $primaryBroker -Force
  557.     Set-RDCertificate -Role RDWebAccess -ImportPath $config.CertPath -Password $Password -ConnectionBroker $primaryBroker -Force
  558.     Set-RDCertificate -Role RDGateway -ImportPath $config.CertPath  -Password $Password -ConnectionBroker $primaryBroker -Force
  559.     Write-Verbose "Configured SSL Certificates"  -Verbose
  560.  
  561. } #end if $config.HADeployment
  562.  
  563.  
  564. Write-Verbose "Stop logging" -Verbose
  565. $EndDate = (Get-Date)
  566. Write-Verbose "Elapsed Time: $(($EndDate-$StartDate).TotalSeconds) Seconds" -Verbose
  567. Write-Verbose "Elapsed Time: $(($EndDate-$StartDate).TotalMinutes) Minutes" -Verbose
RAW Paste Data