rds-deployment-ha-broker/Scripts/RdcbHaPostConfig.ps1 (320 lines of code) (raw):

<# .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")