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

First published on CloudBlogs on Jun, 28 2012

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 http://technet.microsoft.com/en-us/library/bb978526.aspx and the Windows PowerShell Blog at http://blogs.msdn.com/b/powershell/ .

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:windowssystem32> import-module RemoteDesktop PS C:windowssystem32> Get-RDServer -? NAME Get-RDServer SYNTAX 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 http://gallery.technet.microsoft.com/scriptcenter/Install-Desktop-Experience-ae573c09

First, some setup code:

Figure 2: Script lines 1-13

1 [CmdletBinding(SupportsShouldProcess=$true)] 2 param ( 3 [Parameter(Mandatory=$false)] 4 [string] 5 $ConnectionBroker, 6 7 [Parameter(Mandatory=$false)] 8 [switch] 9 $Force 10 ) 11 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!