Thursday, September 13, 2007

Setting Terminal Service Properties in .NET

I recently had the requirement of managing Terminal Service properties in AD by means of MIIS. If you've ever been tasked with this, you may have noticed there are many VBScript and C++ snippets online with very few .NET examples. Therefore, I've decided to post how to accomplish this in .NET for those interested.


Initially, you'd think this is pretty easy...why couldn't I just flow any value through to AD using an advanced attribute flow within an MA rule extension? Well, not in this case. If you look into a user objectClass in AD through ADSIEdit, you'll notice these attributes are not directly exposed. Although I was able to populate some of the values through System.DirectoryServices, not all were accessible. Further research uncovered you can manage Terminal Service properties using the ADSI Extension for Terminal Services User Configuration. This extension is an assembly that allows you to manage Terminal Server user properties though the IADsTSUserEx Property Method. Below is sample code I used to test the functionality.


using TSUSEREXLib;
using System.DirectoryServices;
using System;
using System.Collections.Generic;
using System.Text;

namespace Set_Terminal_Service_Properties
{
class Program
{
static void Main(string[] args)
{
string acctName = "chrisca";
string tsHomeDrive = "H:";
string tsHomeDirectory = "\\\\servername\\tshomedirectory\\";
string tsProfilePath = "\\\\servername\\tsprofilepath\\";
int enableLogon = 1; // enable terminal service logins

DirectoryEntry entry = new DirectoryEntry
("LDAP://CN=Chris Calderon,CN=Users,DC=corp,DC=contoso,DC=com");
ADsTSUserEx oUser = (ADsTSUserEx)entry.NativeObject;
oUser.AllowLogon = enableLogon;
oUser.TerminalServicesHomeDirectory = tsHomeDirectory + acctName;
oUser.TerminalServicesHomeDrive = tsHomeDrive;
oUser.TerminalServicesProfilePath = tsProfilePath + acctName;
entry.CommitChanges();
entry.Close();
}
}
}

As you can see, you use the extension in the same manner as you would any ADSI statements. A key item to consider is, the properties that the Terminal Service User component exposes is not directly mapping individual AD attributes. Common with ADSI, when calling these methods to load the property values of the ADSI object, it stores this information into the property cache of the directory store. Only until the IADs::SetInfo method is called (or something equivalent), the property value changes are saved.


This component consists of one DLL (TSUSEREX.DLL), located within the %SystemRoot%\System32 directory. In order to use the IADsTSUserEx interface, you must reference this assembly within your project. The link below provides a table that lists the property methods of the IADsTSUserEx interface.


IADsTSUserEx Property Methods Details


My original goal is to eventually build an XMA for auxiliary attributes; however the core requirement to do that is to identify a method to access (read/write) these attributes.

1 comment:

Anonymous said...

Very usefull script, thank's for sharing.
After all, I still dont understand why Microsoft choose to use a single directory attributs to store several data ! Are we going to re-invent database in attributs ?