How can I use IADsTSUserEx to modify Active Directory TS properties?

MrDeveloper
MrDeveloper used Ask the Experts™
on
Hello, I'm trying to use IADsTSUserEx to modify a few TS properties of an AD user.  I can modify the user's other properties easily using an DirectoryEntry object.  However, it looks like you can't use that object to modify TS properties (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/ad/user_object_user_interface_mapping.asp - at the bottom).

It pointed me to this page:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/termserv/termserv/iadstsuserex.asp

I tried the sample code that they provide:

        Dim DSO As Object
        Dim usr As System.DirectoryServices.DirectoryEntry

        DSO = GetObject("LDAP:")
        usr = DSO.OpenDSObject("LDAP://CN=rsuser1,OU=MyClientTestOU,DC=MyCompany,DC=com")
        usr.TerminalServicesHomeDirectory = "c:\"
        usr.SetInfo()

I get an error:  'TerminalServicesHomeDirectory' is not a member of 'System.DirectoryServices.DirectoryEntry'.

Is there maybe a reference that I need to add?  I find it odd that they do not reference IADsTSUserEx at all in the sample code.  Any help will be greatly appreciated, this is quite urgent!
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
The link you gave states:

Before calling the methods of this interface, you must call the IADs::GetInfo method or the IADs::GetInfoEx method to load the property values of the ADSI object from the underlying directory store into the property cache. Call IADs::GetInfo to refresh all the property values for the class; call IADs::GetInfoEx to refresh the values of selected properties in the property cache.

Your sample code doesn't call GetInfo or GetInfoEx, so that's probably why it doesn't work. These objects can be a bit funny to work with. The interfaces  that they expose are wired up dynamically as new items are added to the property cache. If you are used to programming with objects whose interfaces don't change, this can lead to a bit of head scratching when you see an error like that. You might find it interesting to check which interfaces are there at a given moment using "typeof". You'll probably find that IADsTSUserEx isn't there until you call GetInfo(Ex).

You could also try dimming a variable of the interface type yourself, although then you would need the reference at compile time. Something like:

' do the GetInfo before you get here

Dim TSUser as IADsTSUserEx
set TSUser = usr
TSUser.TerminalServicesHomeDirectory = "c:\"

' and the setinfo as before

Author

Commented:
Thanks for the help, I ended up finding a 3rd party tool command line exe that could do it.  If anyone is interested, post here and I'll provide details.
How this thing work in Visual c++

but i cannot find the files

TsUserEx.h, TsUserEx_i.c,
TsUserEx.Tlb


Help me!!!!!!!!!
Learn Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

Do you still have the packaging that Visual C++ came in?
No, I have Visual Studio .NEt 2003,
and the newest microsoft sdk (For XP and Windows 2003).
But this files are not included,
and i did't found any description on the internet where to find it!

Sorry - that was a cheap shot! If you read my original answer carefully, you will see that the interfaces are created dynamically. That probably means you'll have to do without a header file.
no in c++ its not working

            IADsUser  *pUser=NULL;
            wchar_t path[IAD_MAXPATH];      

            Trace ("Found an User:%S\nADSPATH: %S", username, buf);

            get_path(path,localdomain_controller, _T(""),_T(""),buf);

            Trace ("Object: %S", path);

            hr = ADsOpenObject(path, localCreditUser,localCreditPassword, get_dwReserved(localdomain_controller)  ,IID_IADsUser,(void**) &pUser );
            if (FAILED(hr))
            {
                        if (pUser)
                        {
                              pUser->Release();      
                              pUser = 0;
                        }
                        swprintf(error_message, L"Error getting User Object, Function ADsOpenObject. %s", ADSGetLastErrorString(hr));
                        return 0;
            }

            hr=pUser->GetInfo();
            hr = pUser->Put(L"TerminalServicesHomeDirectory", CComVariant(L"C:\\"));
            hr=pUser->SetInfo();

the setinfo tells me always that there is an invalid property


Did you try it with a BSTR instead of a Variant?
Also you could try using

hr=pUser->put_TerminalServicesHomeDirectory(&bstrTSHD);

Failing that, you could have a look at the property cache interfaces:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/property_cache_interfaces.asp

This is the error Message of the compiler,

c:\DATA\Atos\Source\REX2\RexLib\RexLib\HActiveDirectory.cpp(1630) : error C2039: 'put_TerminalServicesHomeDirectory' : is not a member of 'IADsUser'
        c:\Program Files\Microsoft SDK\include\Iads.h(10022) : see declaration of 'IADsUser'


the big difference between C++ and VB is, that everything must be defined a compile time,
and it looks like that micrsoft don't want to publish the interface of IADSTsUserex
C++ is capable of everything and more that VB can do. Still - you'll need to use IDispatch I should think.
do you have a idea how to do?

can you also not find this file in your sdk?
TsUserEx.h, TsUserEx_i.c,
TsUserEx.Tlb

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial