Introduction to Windows PowerShell scripting in Windows Server 2012 Remote Desktop Services

Introduction to Windows PowerShell scripting in Windows Server 2012 Remote Desktop Services

Rate This
  • Comments 16

Hello all, my name is Travis Howe and I’m a developer on the Remote Desktop Virtualization team. One of the new features that we’re all very proud of in Windows Server 2012 is a new Windows PowerShell layer, which provides a powerful set of functionality to set up, configure, and control your Windows Server 2012 Remote Desktop Services (RDS) deployments. The feature is too big to cover in one post, but I wanted to give you a quick introduction to help you get started with scripting your deployments in the Windows Server 2012 Release Candidate build. In this post I’ll give a brief overview of the kinds of tasks you can perform by using the new RDS Windows PowerShell layer, and then go a bit more in-depth with one of the Windows PowerShell cmdlets that you’ll likely be using a lot in your scripts (Get-RDServer), and finally finish up with a practical example showing how to use that cmdlet to install the Desktop Experience feature on all of the Remote Desktop Session Host (RD Session Host) servers in your deployment.

To keep this introduction focused on the RDS functionality enabled by our new Windows PowerShell layer, I’ve written this post assuming you have a basic understanding of Windows PowerShell. If you’d like to learn more about Windows PowerShell, a few good places to start are this page on the TechNet Library and the Windows PowerShell Blog at

The RemoteDesktop module

The first step in using the new RDS Windows PowerShell layer in Windows Server 2012 is to load the RemoteDesktop module (using the command import-module RemoteDesktop). This module contains all the new RDS cmdlets. Broadly speaking, the cmdlets in this module can be broken up into the following feature areas:

  • Creating and managing your deployment, including:
    • Adding and removing servers from the deployment (Add/Remove-RDServer)
    • RD Gateway configuration (Get/Set-RDDeploymentGatewayConfiguration)
    • RD Licensing configuration (Get/Set-RDLicenseConfiguration
    • Setting up certificates (New/Get/Set-RDCertificate)
    • High availability (Get/Set-RDConnectionBrokerHighAvailability, etc.)
  • Creating and managing session collections, including:
    • Creating session collections (New/Get/Remove -RDSessionCollection)
    • Managing collection configurations (Get/Set-RDSessionCollectionConfiguration)
    • Managing the RD Session Host servers in your collections (Add/Get/Set/Remove-RDSessionHost)
  • Creating and managing virtual desktop collections, including:
    • Creating virtual desktop collections (New/Get/Remove -RDVirtualDesktopCollection)
    • Managing collection configurations (Get/Set-RDVirtualDesktopCollectionConfiguration)
    • Managing the virtual desktops in your collections (Get-RDVirtualDesktop, Add-RDVirtualDesktopToCollection, Get-RDPersonalVirtualDesktopAssignment, etc.)
    • Managing patching of personal virtual desktop collections (New/Get/Set/Remove-RDPersonalVirtualDesktopPatchSchedule)
  • Session control, including:
    • Monitoring the sessions in your deployment (Get-RDUserSession)
    • Communicating with your users (Send-RDUserMessage)
    • Disconnecting or logging off your users (Disconnect-RDUser, Invoke-RDUserLogoff)
  • RemoteApp and Desktop publishing, including:
    • Publishing remote desktops (Get/Set-RDRemoteDesktop)
    • Publishing RemoteApp programs (Get-RDAvailableApp, New/Get/Set/Remove-RDRemoteApp)
    • Managing published RemoteApp file type associations (Get/Set-RDFileTypeAssociation)

You’ll be hearing more about these feature areas in the coming months. For now, let’s focus on just one of the cmdlets meant for managing your deployment: Get-RDServer.

The Get-RDServer cmdlet

Figure 1: The Get-RDServer cmdlet

PS C:\windows\system32> import-module RemoteDesktop
PS C:\windows\system32> Get-RDServer -?


    Get-RDServer [[-ConnectionBroker] <string>] [[-Role] <string[]>

A good way to quickly familiarize yourself with a cmdlet is to use the built-in help in Windows PowerShell. For Get-RDServer, the output is pretty simple:

As you can see in figure 1, the cmdlet takes two parameters: ConnectionBroker, and Role.

The ConnectionBroker parameter is an optional parameter for many of the cmdlets in the RemoteDesktop module. This is used to specify the FQDN of the server running the RD Connection Broker role service for the deployment (in a high availability deployment, use the FQDN of the RD Connection Broker server that is running the active instance of the Remote Desktop Management Server service. You can control which RD Connection Broker server is running the active instance by using the Set-RDActiveManagementServer cmdlet).

The Role parameter is used here to narrow down which of the RDS roles you are interested in:

  • RDS-VIRTUALIZATION corresponds to the “Remote Desktop Virtualization Host” role service.
  • RDS-RD-SERVER corresponds to the “Remote Desktop Session Host” role service.
  • RDS-CONNECTION-BROKER corresponds to the “Remote Desktop Connection Broker” role service.
  • RDS-WEB-ACCESS corresponds to the “Remote Desktop Web Access” role service.
  • RDS-GATEWAY corresponds to the “Remote Desktop Gateway” role service.
  • RDS-LICENSING corresponds to the “Remote Desktop Licensing” role service.

You can specify one or more of these roles to narrow your results, or you can omit the parameter entirely to return all servers in your deployment.

When run, the cmdlet returns one or more objects of type Microsoft.RemoteDesktopServices.Management.RDDeploymentServer. These objects will contain two properties:

  • Server, a string containing the FQDN of the server
  • Roles, an array of strings describing the roles installed on that server (value will match the allowed values for the Role parameter described above)

Now, I’ll demonstrate how to use this cmdlet in a real-world example.

Installing the Desktop Experience feature on every RD Session Host server in your deployment

Using the Get-RDServer cmdlet in conjunction with a few useful cmdlets from the ServerManager module, we can write a fairly simple script that allows us to enumerate all of the RD Session Host servers in our deployment, and then install the Desktop Experience feature on any servers that do not already have it installed. In a real deployment this would allow your end users to take advantage of the full Windows 8 client experience in their remote sessions.

For brevity, only the “meat” of the script will be presented here. The full script is available on the TechNet Script Center for download at

First, some setup code:

Figure 2: Script lines 1-13

  1 [CmdletBinding(SupportsShouldProcess=$true)]
  2 param (
  3     [Parameter(Mandatory=$false)]
  4     [string]
  5     $ConnectionBroker,
  7     [Parameter(Mandatory=$false)]
  8     [switch]
  9     $Force
 10 )
 12 import-module ServerManager
 13 import-module RemoteDesktop


As you can see in figure 2, our script takes two parameters: ConnectionBroker, and Force. The ConnectionBroker parameter will be passed-through to the Get-RDServer cmdlet as described in the previous section. I won’t go into the Force parameter in this post—briefly, it is used to suppress confirmation prompts. For more information, see the full script on the Script Center.

Also in figure 2, we import two key modules: the ServerManager module, which gives us the cmdlets necessary to control the installed features, and the new RemoteDesktop module, which will let us determine the list of RD Session Host servers in our deployment.

Next, we’ll fetch the list of RD Session Host servers in the deployment:

Figure 3: Script lines 15-24

  15 # Fetch all RDSH servers in the deployment
  16 $sessionHosts = Get-RDServer -Role RDS-RD-SERVER –ConnectionBroker
$ConnectionBroker -ErrorAction Stop 17 if(-not $sessionHosts) 18 { 19 Write-Error "No RD Session Host servers found in the deployment" 20 return 21 } 22 23 $sessionHostsString = $sessionHosts.Server -Join ", " 24 Write-Verbose "Discovered session hosts: $sessionHostsString"


In figure 3 we use the new Get-RDServer cmdlet to retrieve a list of objects representing servers in the deployment that have the RDS-RD-SERVER role (a.k.a. the RD Session Host role) installed. We then write the list of discovered RD Session Host servers to the verbose output (useful in case we need to debug the script down the road).

Next, we’ll check if any of the RD Session Host servers already have the Desktop Experience feature installed:

Figure 4: Script lines 26-51

  26 # Determine which ones don't have desktop experience installed
  27 $toInstall = New-Object System.Collections.ArrayList
  28 foreach($rdsh in $sessionHosts.Server)
  29 {
  30     try
  31     {
  32         $desktopExp = Get-WindowsFeature -Name Desktop-Experience -ComputerName $rdsh -ErrorAction Stop
  34         if($desktopExp.Installed)
  35         {
  36             Write-Host "The Desktop Experience feature is already installed on $rdsh"
  37         }
  38         elseif($desktopExp.InstallState -ne [Microsoft.Windows.ServerManager.Commands.InstallState]::Available)
  39         {
  40             Write-Warning "Cannot install the Desktop Experience feature on $($rdsh): the feature does not appear to be available for installation, the InstallState is listed as '$($desktopExp.InstallState)' instead of 'Available'"
  41         }
  42         else
  43         {
  44             $toInstall.Add($rdsh.ToLower()) | Out-Null
  45         }
  46     }
  47     catch
  48     {
  49         Write-Warning "Cannot install the Desktop Experience feature on $($rdsh): error querying Desktop Experience feature: $_"
  50     }
  51 }

In figure 4 we loop over the list of RD Session Host servers, and use the Get-WindowsFeature cmdlet to determine whether the Desktop Experience feature is already installed, not available for installation, or available to be installed. For all the servers where the feature is available to be installed, we add them to a list for further processing.

I’m going to skip lines 54-93 here because they contain fairly simple code for edge-case handling and prompting the user for confirmation. For details, see the full script on the Script Center.

Finally, we can install the feature on the selected RD Session Host servers:

Figure 5: Script lines 94-99

  94 # Install the feature
  95 foreach($rdsh in $toInstall)
  96 {
  97     Write-Verbose "Installing Desktop-Experience on machine $rdsh"
  98     Install-WindowsFeature -Name Desktop-Experience –Restart
-IncludeAllSubFeature -IncludeManagementTools -ComputerName $rdsh 99 }

In figure 5 we loop over the list of RD Session Host servers, and use the Install-WindowsFeature cmdlet to install the Desktop Experience feature.

And that completes our script: we’ve gathered the list of RD Session Host servers by using the new Get-RDServer cmdlet, and with the help of some commands from the ServerManager module, made sure that the Desktop Experience feature is installed on all of them.

I hope this introduction has been helpful. There’s a lot of functionality in the new RemoteDesktop module, so I encourage you to dive in and start scripting your deployment!

Leave a Comment
  • Please add 8 and 3 and type the answer here:
  • Post
  • Excellent stuff!

  • Great article, good example scripts!

    Kind regards,

    Freek Berson

  • How do you create a new RDP Listener in Server 2012?

  • Hey Travis,

    Win32_ServerFeature class has been deprecated. This class works for Win2k8 R2 and below.

    Can you tell us how to enumerate the windows 2012 server feature programmatically?



  • Hi Irfan,

    Good catch, thanks for letting me know. I'll investigate and update here as soon as I can.



  • Hi all,

    I wanted to follow-up on my last comment. I've verified that Win32_ServerFeature is deprecated in Server 2012. It looks like the replacements are the Server Manager cmdlets:

    I will update the sample script and blog post contents to use these cmdlets as soon as I can find some time.



  • is there a way to use scripts so we can RDS work in a workgroup environment

  • humm...

    Where do I put a recomendation for a printable version?!?

  • WTF..... Are you MS developers smoking crack? Got a head injury?

    I just want to know which other Tech in connected to my DC.

    Take out the 100% functional way are replace with BS code to screw everyone.

    You can shove this article up your ***!

  • For the love of all that's holy, please put back the 2008 R2 RDS management functions.  2012 is a giant step backwards (or sideways).  Let Linux be the master of CLI stuff, at least provide the same or better functionality in newer OS's.   Way to make our jobs harder.  Really appreciate it.

    Or, I guess the other way to look at it is Microsoft's Surface & Windows 8 divisions are tanking so badly they had to make up for it by REQUIRING training classes for normally expert users to figure out how to do simple tasks.

  • Ok, sorry but I really love PS and I am a bit disappointed at a couple of major failings in RDS. If you can help me, great. Maybe I missing something here.

    I can fine no way to determine what application is being run in a session. I can get session collections of a collection but unless I limit that collection to one application (real dumb) I have no way to know.

    PowerShell or GUI has same limitation. What is purpose of collections if I cannot see what application is being run? This is a major hold up and anything more that a few applications is not scalable. It looks like another year of Citrix maintenance. :(


  • I agree with WTF and JW. I have enough to do without learning to script every damn thing. This is Windows not Linux!  I'll be sticking with 2008 r2 until forced to do otherwise. And what's with the crappy interface?  Looks like Windows 3.11!

  • I also agree with WTF & JW...  and i'll add what's with the " you must constantly manually refresh " to see any status changes in windows Task Scheduler?!!!   don't MS developers use these tools?  surely if they did they'd correct these shortcomings!

  • I completely disagree with the GUI users. PowerShell is the way to follow, to automate IT.

    Computers have to work for humans, not-viceversa.

    If learning how to create or use a simple script is too hard for you, I'm sorry, maybe you didn't even try ?, but in my opinion IT is engineering, not clicking. VMS and MVS and Unix and many others got it sooner.

    (Even though Microsoft and others are trying to sell computers to everyone who will never read a manual)

  • Thanks for the powershell scripts. I'm trying to automate all parts of our RDS setup, but the Powershell RDS scripts return inconsistent results, depending on where and how I call them.

    Others are experiencing similar problems:

    Look at this example. I'm executing Powershell from the server:

    PS C:\> Import-Module RemoteDesktop

    PS C:\> Get-RDServer -ConnectionBroker

    Server                                             Roles                                                                            

    ------                                             -----                                                                            

    RDS.EXAMPLE.COM                                    {RDS-RD-SERVER, RDS-CONNECTION-BROKER, RDS-WEB-ACCESS, RDS-GATEWAY}              

    Great that worked. But executing at the RDS server through another doesn't.

    PS C:\> Enter-PSSession

    []: PS C:\> Import-Module RemoteDesktop

    []: PS C:\> Get-RDServer -ConnectionBroker

    Get-RDServer : The RD Connection Broker server is not available. Verify that you can connect to the RD Connection Broker server.

       + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException

       + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-RDServer

    In addition, the calling user can't be a local administrator. What's the cause of this? Is there any documentation regarding this?

Page 1 of 2 (16 items) 12