Manage RDS RemoteApp with Windows PowerShell

In Windows Server 2008 R2, Remote Desktop Services (formerly Terminal Services) includes a provider for managing RDS using Windows PowerShell. You may find more information along with some examples in this article on Microsoft TechNet.

One of the many things you can manage this way is the new RemoteApp-feature introduced with Windows Server 2008. In Windows Server 2008 R2, this feature got enhanced by the addition of User Assignment and Web Single Sign-On capabilities. These new features makes it possible for more and more customers to consider RDS without additional products like Citrix. One benefit using Citrix are more flexible application-management, since an published application may be available from a new farm member without adding each application manually.

Lets look at a given example: You got a farm with 16 RDS-servers, and youre leveraging the RemoteApp-feature. For each server in the farm, you must manually set up all applications in RemoteApp-manager after theyre installed. Although there is an export/import-feature in the GUI, many customers require no manual interaction in the server provisioning process. By the addition of the new PowerShell-provider for RDS, this is now possible in RemoteApp using scripting as part of either server provisioning or Group Policy.

For the average Windows sysadmin, I imagine that managing RemoteApp using the RDS PowerShell provider might be a bit tedious. To make this a little easier Ive created a Windows PowerShell module for working with RDS RemoteApp, available from here.

This module contains the following functions:

  • Get-RDSRemoteApp
  • Export-RDSRemoteApps
  • Import-RDSRemoteApps
  • New-RDSRemoteApp
  • Remove-RDSRemoteApp

The functions let you administer the same application attributes as the graphical RemoteApp Manager:

  • Displayname
  • Alias
  • Command-line arguments
  • RD Web Access availability
  • User Assignment

 

Installing the RDSRemoteApp module

Download and unzip RDSRemoteApp.zip in the following location: %userprofile%DocumentsWindowsPowerShellModulesRDSRemoteApp

Alternatively you may save the module in any of the folders in the $Env:PSMODULEPATH variable.

Using the RDSRemoteApp module

First well have a look at the RemoteApp Manager application-list in the lab-environment:

image

Start Windows PowerShell on the RDS-server and import the module (you will need to run PowerShell with Administrative privileges):

image

Since Ive leveraged the built-in help capabilities in Windows PowerShell v2 Advanced Functions, I`ll show the usage of the functions with a few screenshots from the help:

Get-RDSRemoteApp

image

New-RDSRemoteApp

image

Remove-RDSRemoteApp

image

Export-RDSRemoteApps

image

Import-RDSRemoteApps

image

Sample usage for export/import:

image

Be aware that there are several other RDS settings that may be managed using the PowerShell provider, this module only leverages the RemoteApp functionality. If someone want to create a module for managing other aspects of RDS, feel free to include my RDSRemoteApp module. And as always, suggestions for improvements and new functionality are more than welcome.

Manage Windows Update installations using Windows PowerShell

In most domains Windows Update are controlled by Group Policy and Windows Server Update Services (WSUS). For client computers, its common to download and install updates automatically. For servers, we want to control the installation of Windows Updates inside a scheduled maintenance window, and hence the Windows Update settings are configured not to automatically install updates.

If there are a few servers to manage, it wont be that time consuming to log on to each server with Remote Desktop and do the Windows Update installations manually. In larger environments however, this wont be an option, it must be automated in some way. While enterprise environments typically invest in a commercial product like BigFix for patch management, this might be overkill or too expensive for environments smaller than an enterprise.

To manage Windows Update in an automated way we can access the Windows Update Agent API using a COM-object called Microsoft.Update.Session. Using the New-Object cmdlet in Windows PowerShell, its easy to work with this COM-object. Based on this COM-object and portions of James ONeills functions for managing Windows Update, Ive written a PowerShell-script called Invoke-WindowsUpdate.

This script is intended to be used to download and install Windows Updates on servers. It runs like expected when invoked from a local computer, however, invoking the script using PowerShell Remoting like I was planning turned out to be problematic: Invoke-Command -ComputerName ServerA -FilePath 'C:ps-scriptsWindows UpdateInvoke-WindowsUpdate.ps1'

This will return the following error message:
Exception calling "CreateUpdateDownloader" with "0" argument(s): "Access is denied. (Exception from HRESULT: 0x80070005 E_ACCESSDENIED))"

This issue doesnt seem to be related to PowerShell, as there are several others reporting the same problem in other languages like VBScript.

The common workaround is to schedule the script to run as a scheduled task running as SYSTEM. Ive chosen to use this approach and to use PowerShell Remoting to invoke the scheduled task to run the script. An example:

$servers = Get-Content 'C:ps-scriptsWindows UpdateBulkA.txt'
foreach ($server in $servers) {
Invoke-Command -Computer $server -ScriptBlock {schtasks /run /tn "PowerShell - download and install Windows Updates"}
}

To create the scheduled task I would recommend you to use Group Policy Preferences.
A few sample screenshots from my lab setup:

image

image

image

image

Although its possible to invoke the script on all servers in the domain at once using i.e. the Active Directory-module for PowerShell to get the server names, I would recommend to break down the installations in several bulks. This way you can control that all domain controllers doesnt go offline at the same time and so on.

As you can see in the script its also possible to enable reporting to e-mail or file (HTML) to a central location, in addition to control whether the servers should reboot if required.
Planned improvements include nicer reports, Windows Update settings in the reports and if possible make the script work without having to use scheduled tasks. Suggestions for other improvements are always welcome.

Backing up Group Policy Objects using Windows PowerShell

A best practice in domain environments are backing up the Group Policy Objects regularly. Even though a GPO may be restored by restoring a system state backup from a domain controller to an alternate location, and then copy the contents from the deleted GPO to a new GPO to restore the settings, this may be a hazzle since its not pretty straightforward. It also requires you to restart the domain controller affected in Directory Services Restore Mode.
PowerShell MVP Don Jones has written a good article on this topic, available here.

For those of you who may not want to do GPO restore the hard way, or buy a commercial third party product, I would encourage you to schedule regular GPO backups using the Windows PowerShell Group Policy-module available in Windows Server 2008 R2, as well as RSAT in Windows 7.
To accomplish this, I
ve written a small script which backs up all modified GPO`s in the specified timespan. I would generally recommend to have the script run once a day, thereby setting the timespan-variable to the last 24 hours. The script are called Backup-ModifiedGPOs.ps1, and available from here.

All Group Policy Objects modified in the specified timespan are backup up to the specified backup path.
Also, an HTML-report are created for each GPO-backup, with the unique backup GUID as part of the filename. This way you can easily see what settings each backup contains.

When restoring a GPO, you must first note the GUID of the backup you want to restore. Then you can restore the GPO by using the Restore-GPO cmdlet in the Group Policy-module. Sample usage:

image

Administrators who feels more comfortable working with the GUI, may use the Group Policy Management Console to do the restore.

The following procedure from the Group Policy Planning and Deployment Guide on Microsoft TechNet describes how to accomplish the restore operation from the GUI:

To view the list of GPO backups

  1. In the GPMC console tree, expand the forest or domain that contains the GPOs that you want to back up.
  2. Right-click Group Policy Objects, and the click Manage Backups.
  3. In the Manage Backups dialog box, enter the path to the location where you stored the GPO backups that you want to view. Alternatively, you can click Browse, locate the folder that contains the GPO backups, and then click OK.
  4. To specify that only the most recent version of the GPOs be displayed in the Backed up GPOs list, select the Show only the latest version of each GPO check box. Click Close.

Using the GPMC to restore GPOs

You can also restore GPOs. This operation restores a backed-up GPO to the same domain from which it was backed up. You cannot restore a GPO from a backup into a domain that is different from the GPO’s original domain.

To restore a previous version of an existing GPO

  1. In the GPMC console tree, expand Group Policy Objects in the forest or domain that contains the GPOs that you want to restore.
  2. Right-click the GPO that you want to restore to a previous version, and then click Restore from Backup.
  3. When the Restore Group Policy Object Wizard opens, follow the instructions in the wizard, and then click Finish.
  4. After the restore operation completes, a summary will state whether the restore succeeded. Click OK.

To restore a deleted GPO

  1. In the GPMC console tree, expand the forest or domain that contains the GPO that you want to restore.
  2. Right-click Group Policy Objects, and then click Manage Backups.
  3. In the Manage Backups dialog box, click Browse, and then locate the file that contains your backed-up GPOs.
  4. In the Backed up GPOs list, click the GPO that you want to restore, and then click Restore.
  5. When you are prompted to confirm the restore operation, click OK.
  6. After the restore operation completes, a summary will state whether the restore succeeded. Click OK. Click Close.

Important: Since Group Policy links are stored on the Organizational Unit objects in Active Directory, this information are not backup up and also not restore. However, the HTML backup-reports contains this information, so you may manually re-link the GPO to the correct OU(s).

Also note that WMI filters and IPSec policies are not backed up by the backup feature in the Group Policy Management Console. For more information on how to manage these items, see the before mentioned Group Policy Planning and Deployment Guide.

 

Dynamic Remote Desktop Connection Manager connection list

Microsoft recently released a free tool for managing multiple remote desktop connections called “Remote Desktop Connection Manager”.

A sample screenshot:

image

There are several nice features, such as “Connect group” which lets you connect to all servers in a group at once:

image

On the “Group Properties” you may set common settings for all connections in the group, like logon credentials:

image

Further, there are group properties for RDS Gateway (formerly TS Gateway), display settings, local resources and so on.

There are several applications for remote desktop connections on the market, and some of them got these settings as a per server setting. Its nice to be able to group servers and configure common settings.

Dynamically creating the connection list

When you work in larger environments with hundreds, maybe thousands of servers, setting up each connection manually isnt an option.

Since Remote Desktop Connection Manager stores the config-files in xml-files, its rather easy to create dynamic config-files for a domain using Windows PowerShell. Ive created a script to accomplish this, called New-RDCManFile.ps1, available from here. It uses Microsofts PowerShell-module for Active Directory, which is available in Windows Server 2008 R2 and RSAT for Windows 7.

The script does the following:
Creates a template xml-file
Inserts the logged on user
s domain name in the file properties
Inserts the logged on users domain name in the group properties
Inserts the logged on user
s username in the logoncredentials section
Inserts the logged on users domain name in the logoncredentials section
Retrieves all computer objects from Active Directory with the word “server” in the operatingsystem property
Adds each computer object as a server object
Saves the XML-file to %userprofile%domain-name.rdg

When done you can open the rdg-file in Remote Desktop Connection Manager. I would recommend you to insert your password in the Group Properties to avoid being asked for credentials for each connection.

Feel free to customize the script to your needs, in example by editing the XML-template to edit the Group Properties. Another customization might be creating a group for each server OU for enhanced overview in larger environments.

If you would rather use Quests PowerShell Commands for Active Directory (which works on downlevel operatingsystems like Windows XP and Windows Server 2003), or any other way to retrieve the server names, you may customize this on line 110.

You might also want to schedule the script to run on a regular basis, saving the file to a central location. This way the IT personnel will always have access to the latest version with the most recent servers added.

If you got any further ideas or comments, please let me know in the comments section below.