Click here to Skip to main content
Click here to Skip to main content

Configuring Terminal Services Gateway Using WMI

, 7 Jul 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Describes methods to add and to remove RAPs from Terminal Services Gateway using WMI.

Introduction

This article is about WMI and the Terminal Services Gateway. You can find a way to manage your TS Gateway server remotely by using WMI. Here, I describe two methods, to add and to remove a Resource Authorization Policy (RAP). All code blocks are picked from a proof-of-concept demo, and they do not represent "in production" state of the code.

Background

Employees that are away from office premises are in constant need of accessing internal resources. Letting people to access their own office computer gives the most familiar feeling while being away. When opening such connections from the Internet, some measures to secure, manage, and handle these connections are needed. To do this without burdening the administrators, an automatic service that does the Terminal Services Gateway configuration for the end-user was developed. This article shows a way to manage one part of the TS Gateway server configuration.

Using the Code

The System.Management namespace needs to be added before the code works. Also, the methods expect you to have a user group on your server. The name of the group in this case is 'RAP_TEST'. If you are part of a domain or if you have an Active Directory service running, you can use 'DOMAIN\UserGroup' like groups as well.

RAP_TEST group on a server

When executing the code, be aware that the authentication level of PacketPrivacy can not be achieved locally. This means that you are not able to run the code on the server you are trying to configure.

First, I start with the code that uses the class described later on. This is a simple loop that adds 100 RAPs to the server.

public class ProofOfConcepts
{
    static void Main(string[] args)
    {
        TerminalServicesGatewayConnector oTSC = 
          new TerminalServicesGatewayConnector("TSGWTEST");

        string log = "";
        for (int i = 0; i < 100; i++)
        {
            oTSC.AddRAP("COUNT_TEST_" + i.ToString(), out log);
            Console.WriteLine("#\t" + i.ToString() + "\t" + log);
        }
        Console.ReadLine();
    }
}

The main point of the article starts by defining the TerminalServerGatewayConnector class. This class is used to connect and make configuration changes. Methods found later from the article are methods of this class.

using System.Management;

public class TerminalServicesGatewayConnector
{
    public enum SUCCESS : byte
    {
        SUCCESS = 0x00,
        ERROR = 0x01,
        REMOTE_EXCEPTION = 0x02
    }

    private ConnectionOptions _oConn;
    private ManagementScope _oMScope;
    private ManagementPath _oMPath;

    private string _sHost;
    private string _sPath = @"\root\CIMV2\TerminalServices";

    private string _sUsername = @"TSGWTEST\Administrator";
    private string _sPassword = @"Password!Admin";

    public TerminalServicesGatewayConnector(string sHost)
    {
        _sHost = @"\\" + sHost;
    }
}

The variables _sUsername and _sPassword need to be set corresponding to your own setup. The namespace variable _sPath is the place where all the WMI calls can be found for the Terminal Services Gateway server. I have heard that Terminal Services will be renamed to Remote Desktop Services. This will probably affect the namespace in future.

Here is the method to add a RAP to the gateway configuration:

public SUCCESS AddRAP(string sComputerName, out string sLogString)
{
    try
    {
        _oConn = new ConnectionOptions();
        _oConn.Impersonation = ImpersonationLevel.Impersonate;
        _oConn.Authentication = AuthenticationLevel.PacketPrivacy;
        _oConn.Username = _sUsername;
        _oConn.Password = _sPassword;
        _oConn.EnablePrivileges = true;

        _oMScope = new ManagementScope(_sHost + _sPath, _oConn);
        _oMScope.Options.Authentication = AuthenticationLevel.PacketPrivacy;
        _oMScope.Options.Impersonation = ImpersonationLevel.Impersonate;
        _oMScope.Options.EnablePrivileges = true;

        _oMPath = new ManagementPath();
        _oMPath.ClassName = "Win32_TSGatewayResourceAuthorizationPolicy";
        _oMPath.NamespacePath = _sPath;

        _oMScope.Connect();

        ManagementClass processClass = new ManagementClass(_oMScope, _oMPath, null);

        ManagementBaseObject inParameters = 
            processClass.GetMethodParameters("Create");
        ManagementObject processInstance = processClass.CreateInstance();
        ManagementNamedValueCollection mnvc = new ManagementNamedValueCollection();
        InvokeMethodOptions imo = new InvokeMethodOptions();

        inParameters["Name"] = sComputerName + "_GW";
        inParameters["Description"] = "";
        inParameters["Enabled"] = true;
        inParameters["ResourceGroupName"] = @"RAP_TEST";
        inParameters["ResourceGroupType"] = "CG";
        inParameters["UserGroupNames"] = @"RAP_TEST";
        inParameters["ProtocolNames"] = "RDP";
        inParameters["PortNumbers"] = "3389";

        mnvc.Add("Authentication", AuthenticationLevel.PacketPrivacy);
        imo.Context = mnvc;
        sLogString = "";
        processClass.Get();
        ManagementBaseObject outParameters = 
          processClass.InvokeMethod("Create", inParameters, imo);

        if ((UInt32)outParameters["ReturnValue"] == 0)
        {
            sLogString = "Item created.";
            return SUCCESS.SUCCESS;
        }
        else
        {
            sLogString = "ERROR: " + 
              ((UInt32)outParameters["ReturnValue"]).ToString();
            return SUCCESS.ERROR;
        }
    }
    catch (System.Exception ex)
    {
        sLogString = ex.Message;
        return SUCCESS.REMOTE_EXCEPTION;
    }
}

Here is the method to delete a RAP from a gateway configuration:

public SUCCESS DeleteRAP(string sComputerName, out string sLogString)
{
    try
    {
        _oConn = new ConnectionOptions();
        _oConn.Impersonation = ImpersonationLevel.Impersonate;
        _oConn.Authentication = AuthenticationLevel.PacketPrivacy;
        _oConn.Username = _sUsername;
        _oConn.Password = _sPassword;
        _oConn.EnablePrivileges = true;

        _oMScope = new ManagementScope(_sHost + _sPath, _oConn);
        _oMScope.Options.Authentication = AuthenticationLevel.PacketPrivacy;
        _oMScope.Options.Impersonation = ImpersonationLevel.Impersonate;
        _oMScope.Options.EnablePrivileges = true;

        _oMScope.Connect();

        ObjectQuery oQuery = new ObjectQuery("SELECT * FROM " + 
          "Win32_TSGatewayResourceAuthorizationPolicy WHERE Name=\"" + 
          sComputerName + "_GW\" ");

        ManagementObjectCollection oResults = 
            new ManagementObjectSearcher(_oMScope, oQuery).Get();
        if (oResults != null && oResults.Count == 1)
        {
            foreach (ManagementObject oResult in oResults)
            {
                uint iResultCode = 
                  (UInt32)oResult.InvokeMethod("Delete", null);
                if (iResultCode == 0)
                {
                    sLogString = "Item deleted.";
                    return SUCCESS.SUCCESS;
                }
                else
                {
                    sLogString = "ERROR: " + iResultCode.ToString();
                    return SUCCESS.ERROR;
                }
            }
        }
        sLogString = "ERROR: Not Found.";
        return SUCCESS.ERROR;
    }
    catch (System.Exception ex)
    {
        sLogString = "ERROR: " + ex.Message;
        return SUCCESS.REMOTE_EXCEPTION;
    }
}

Points of Interest

The data source for RAPs on the Terminal Services Gateway server is not designed for concurrent access. Be aware of that fact when writing a program to access these settings. Accessing RAP configuration concurrently can corrupt the RAP storage. To avoid this problem, I created a Mutex to shield concurrent access programmatically.

History

  • 2009-06-29 - First version.
  • 2009-07-08 - Spelling corrections.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Petri Lehtonen
Software Developer CERN
Finland Finland
Have been working with .NET since 2002. Familiar with C#, ASP.NET and VB.NET.

Comments and Discussions

 
QuestionAdditional resources for configuring terminal services PinmemberEC4IT21-Sep-11 9:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411023.1 | Last Updated 8 Jul 2009
Article Copyright 2009 by Petri Lehtonen
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid