In this part we will see how we can automate RDS deployment with Desired State Configuration (DSC).
If you are working with RDS and if you are installing / re-installing it a lot then DSC is the perfect tool for you. We live in a world of automation and we don’t have time to click us through the wizard over and over again every time we need to rebuild our deplyoment and start from scratch.
I will run configuration from DC01. All servers are domain joined.
INFO! In this demo I will use plain text password. Be sure to protect the password with certificate in a production environment.
Infrastructure:
DC01 -> Domain Controller
RDCB01 -> Will become Connection Broker and Licensing server
RDSH01 -> Will become Session Host
RDWA01 -> Will become Web Access
Before we go deep into the configuration, there are some prerequisite that we need to fulfill before we can make this work.
Prerequisites:
- Configure LCM (Local Configuration Manager) on the target servers
- Make sure that the DSC resources exist on both source and target servers
So the first thing we need to do is to configure LCM. There are 3 settings that are important to us: ActionAfterReboot, ConfigurationMode and RebootNodeIfNeeded
ActionAfterReboot –> Specifies what happens after a reboot during the application of a configuration. Default is ContinueConfiguration so unless you didn’t change this you are good to go. If yes, change it back to defaults by adding ActionAfterReboot = ‘ContinueConfiguration’
Next is ConfigurationMode
LCM has 3 configuration modes:
- ApplyOnly –> This is one shoot. DSC applies the configuration and that’s it. It does not check for drift from a previously configured state.
- ApplyAndMonitor –> This is the default value. After initial application of a new configuration, if the target node drifts from the desired state, DSC reports the discrepancy in logs
- ApplyandAutoCorrect –-> After initial application of a new configuration, if the target node drifts from the desired state, DSC reports the discrepancy in logs, and then re-applies the current configuration. So if you change something on the server DSC will detect that and revert the change to desired state which is specified in config file (MOF)
I chose ApplyOnly, because ApplyAndAutoCorrect is overkill for what I need.
Last but not least is the RebootNodeIfNeeded. Set this to $true to automatically reboot the node after a configuration that requires reboot is applied. Otherwise, you will have to manually reboot the node for any configuration that requires it. Session host server will require reboot.
Let’s configure the LCM first.
[DscLocalConfigurationManager()] configuration LCM { param ( [parameter(Mandatory=$true)] [string[]]$computername ) node $computername { settings { ConfigurationMode = 'ApplyOnly' RebootNodeIfNeeded = $true } } } $computername = 'RDCB01','RDSH01','RDWA01' LCM -OutputPath 'C:\DSC' -computername $computername -verbose
This will generate 3 meta.mof files. meta.mof files hold configuration for LCM.
Let’s push these configs to our target servers.
Set-DscLocalConfigurationManager -Path ‘C:\DSC’ -Force -Verbose -ComputerName $computername
-verbose -> This will give us some additional information as it runs
To confirm, we can use invoke-command and remote to the destination computers.
Our next requirement is to download required DSC module. Key to point here is that everytime when you are configuring something like RDS, DCHP, WebServer etc. you will need to have modules on source and destination servers.
Required Module:
- xRemoteDesktopSessionHost
INFO!!!! Before you go and install this module from repository you will have to know that you will not be able to configure RDS across 3 or more nodes without modifying the module and removing some code. If you install it and try to do the same thing we are doing here you will run into issues with session collection and you will never be able to configure session collection settings etc. I modified the resources in that module and you can download and install them from here.
xRemoteDesktopSessionHost
Before we go and use this module, let’s explore it.
Get-DscResource -Module xRemoteDesktopSessionHost
We can see here resources that we can use to build our RDS deployment.
We can use -syntax to further explore resources and to see how we can use them and which one is mandatory.
Once we know that we can start to build our configuration. Be sure to have that module on all servers that will participate in configuration.
Now, let’s install and configure RDS
Whole code
$data = @{ AllNodes = @( @{ NodeName = '*' PSDscAllowPlainTextPassword = $true PSDscAllowDomainUser = $true }, @{ NodeName = 'rdcb01.mehic.se' Role = 'Connection Broker' }, @{ NodeName = 'rdsh01.mehic.se' Role = 'Session Host' }, @{ NodeName = 'rdwa01.mehic.se' Role = 'Web Access' } ); RDSData = @{ ConnectionBroker = 'rdcb01.mehic.se' SessionHost = 'rdsh01.mehic.se' WebAccessServer = 'rdwa01.mehic.se' CollectionName = 'NM' AutomaticReconnectionEnabled = $true DisconnectedSessionLimitMin = 360 IdleSessionLimitMin = 360 BrokenConnectionAction = 'Disconnect' UserGroup = 'RDS Users' LicenseServer = 'rdcb01.mehic.se' LicenseMode = 'PerUser' } } Configuration RDS { param ( [Parameter(Mandatory=$true)] [pscredential]$domainadmin ) #region DSC Resource Modules #OBS!!! Be sure that the modules exist on the destination host servers Import-DscResource -ModuleName PSDesiredStateConfiguration, @{ModuleName='xRemoteDesktopSessionHost';ModuleVersion="1.8.0.0"} #endregion Node $AllNodes.Where{$_.Role -eq 'Connection Broker'}.NodeName { $RDData = $data.RDSData WindowsFeature RDSConnectionBroker { Name = 'RDS-Connection-Broker' Ensure = 'Present' } WindowsFeature RDLicensing { Ensure = "Present" Name = "RDS-Licensing" } WaitForAll SessionHost { NodeName = 'rdsh01.mehic.se' ResourceName = '[WindowsFeature]SessionHost' RetryIntervalSec = 15 RetryCount = 50 DependsOn = '[WindowsFeature]RDLicensing' } WaitForAll WebAccess { NodeName = 'rdwa01.mehic.se' ResourceName = '[WindowsFeature]WebAccess' RetryIntervalSec = 15 RetryCount = 50 DependsOn = '[WaitForAll]SessionHost' } xRDSessionDeployment NewDeployment { ConnectionBroker = $RDData.ConnectionBroker SessionHost = $RDData.SessionHost WebAccessServer = $RDData.WebAccessServer DependsOn = '[WaitForAll]WebAccess' PsDscRunAsCredential = $domainadmin } xRDSessionCollection collection { CollectionName = $RDData.CollectionName SessionHost = $RDData.SessionHost ConnectionBroker = $RDData.ConnectionBroker DependsOn = '[xRDSessionDeployment]NewDeployment' PsDscRunAsCredential = $domainadmin } xRDSessionCollectionConfiguration collectionconfig { CollectionName = $RDData.CollectionName ConnectionBroker = $RDData.ConnectionBroker AutomaticReconnectionEnabled = $true DisconnectedSessionLimitMin = $RDData.DisconnectedSessionLimitMin IdleSessionLimitMin = $RDData.IdleSessionLimitMin BrokenConnectionAction = $RDData.BrokenConnectionAction UserGroup = $RDData.UserGroup DependsOn = '[xRDSessionCollection]collection' PsDscRunAsCredential = $domainadmin } xRDLicenseConfiguration licenseconfig { ConnectionBroker = $RDData.ConnectionBroker LicenseServer = $RDData.LicenseServer LicenseMode = $RDData.LicenseMode DependsOn = '[xRDSessionCollectionConfiguration]collectionconfig' PsDscRunAsCredential = $domainadmin } } Node $AllNodes.Where{$_.Role -eq 'Session Host'}.NodeName { WindowsFeature SessionHost { Name = 'RDS-RD-Server' Ensure = 'Present' } } Node $AllNodes.Where{$_.Role -eq 'Web Access'}.NodeName { WindowsFeature WebAccess { Name = 'RDS-Web-Access' Ensure = 'Present' } } } RDS -OutputPath 'C:\DSC Configuration' -domainadmin $domainadmin -ConfigurationData $data -Verbose
Run the code and specify account with domain admin privileges. This will create 3 mof files.
Push the configuration to the remote servers with
Start-DscConfiguration -ComputerName $computername -Wait -Verbose -Force -Path ‘<path to the mof files>’
That’s it. Now what if we want to publish some remote app? One thing to know about DSC is that you never touch the machine. When you implement DSC in your environment you will administer everything through the DSC, you will not go to the machine and start configure it after you push/pull the config. DSC can minimize human error as well. Now if you want to deploy RDS with remote apps instead you will need to add xRDRemoteApp resource to it.
xRDRemoteApp chrome { CollectionName = $RDData.CollectionName Alias = 'Chrome' DisplayName = 'Chrome' FilePath = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' DependsOn = '[xRDLicenseConfiguration]licenseconfig' PsDscRunAsCredential = $domainadmin }
I added just 1 remote app (Chrome) but you can add many more.
That’s it. I hope this has been informative for you. If I find time I will make few posts with DSC which will show you how we can configure DC, DNS, DHCP, join machines to domain and configure roles and features and much more.
Stay Tuned!
Cheers,
Nedim
brilliant sequence of posts!
LikeLiked by 1 person
Thank you Nedim for this one. I hope to see more DSC and RDS posts. You have the best content and the site on the whole internet. Keep up with good work.
Greetings from Germany
LikeLiked by 1 person
Great post Nedim, many thanks. Looking forward for more automation in RDS services.
LikeLiked by 1 person
Excellent post. Are you going to post automation with rd gateway, remote apps as well. Would be nice to see whole deploymeny.
P.S:. Great site
LikeLiked by 1 person
Many thanks for this one. Excellent content on the page.
LikeLiked by 1 person
God Bless you man, best remote desktop services walkthrough series I have ever seen.
LikeLiked by 1 person
Brilliant post Nedim, thanks for this one.
LikeLiked by 1 person
Best RDS / DSC tutorial on the internet, thank you so much Nedim. Greeting from Australia.
LikeLike
Thank you Luyang. I will cover DSC in another section. There will be ca 10 posts covering dsc in deep and installing complete environment with dc’s rds dhcp etc. Stay tuned.
Best Regards
Nedim
LikeLike
awesome, thanks a lot
LikeLiked by 1 person
Great post about RDS automation Nedim. I have a question is this possible to create configuration for 2x Session hosts, 2x web-access and 2x connection broker using this module? I tried to play around with this script but I’m getting compilation errors.
LikeLike
Hi,
Thank you. Do you mean to configure Broker HA?
LikeLike