RemkoWeijnen.nl

About Terminal Server, Citrix, Delphi and other stuff

Archive for the ‘Active Directory’ Category

I needed to obtain the Fully Qualified Domain Name (FQDN) for a given NetBios domain name. Eg from MYDOMAIN to dc=mydomain,dc=local.

I did some tests with the TranslateName API and if you append a \ to the domain name it returns the FQDN.

Here is a short example:

(more…)

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Random Active Directory Notes #4

Previously I discussed IDirectoryObject, today I will show how to change a user’s password with IDirectoryObject.

I didn’t find any documentation except a kb article describing how to use pure ldap to do it. Of course I could have used IADsUser::SetPassword but I decided not to because of the following reasons:

  • IADs interfaces are terribly slow (although for one use you probably wouldn’t really notice).
  • IADsUser::SetPassword tries 3 different methods to set the password (ldap over ssl, kerberos and finally NetUserSetInfo) which makes it even slower (most domain controllers do not have an ssl certificate) and unpredictable.

All example code I found was .NET based using the .NET wrappers for Active Directory and seemed to be meant for use in Adam rather than full Active Directory (it set port number to 389 and password mode to cleartext).

In the end it’s not very difficult but nonetheless it took me a while before I got it right.

We can write to the unicodePwd attribute which wants the password as a double quoted unicode string. If you look at this attribute with AdsiEdit you’ll see that the type is Octet String and that it can be written only.

I was tricked with Delphi’s QuotedStr function for a while because it doesn’t return a double but single quoted string ;-)

Below a small snippet from the upcoming JwsclActiveDirectory that shows how to use it: (more…)

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Using Windows Dialogs from Delphi

Today I reused a unit I wrote a long time ago for TSAdminEx that shows Resource Dialogs from DLL’s or Executables. I wrote it for a couple of reasons:

  • Reusing existing dialogs is conventient since the user already knows it.
  • Windows takes care of translating it into the user’s language.
  • I am too lazy to recreate them ;-)

The code is hardly rocket science and could probably be improved and made more sophisticated but it works for me. I decided to share it since you may find it usefull.

Here is a small usage example that shows the Reset Password dialog from Active Directory Users & Computers. This dialog is in dsadmin.dll (on Windows Vista/7 you will find it in ds.admin.dll.mui in the language subfolder eg %systemroot%\system32\en-US but you can load it using just the dll name).

It looks like this:

215 DIALOGEX 0, 0, 252, 139
STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CONTEXTHELP
CAPTION "Reset Password"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
FONT 8, "MS Shell Dlg"
{
   CONTROL "&New password:", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 10, 79, 10
   CONTROL "", 220, EDIT, ES_LEFT | ES_PASSWORD | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 92, 7, 153, 14
   CONTROL "&Confirm password:", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 28, 79, 10
   CONTROL "", 222, EDIT, ES_LEFT | ES_PASSWORD | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 92, 25, 153, 14
   CONTROL "&User must change password at next logon", 261, BUTTON, BS_AUTOCHECKBOX | BS_LEFT | BS_TOP | BS_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 46, 237, 10
   CONTROL "The user must logoff and then logon again for the change to take effect.", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 14, 61, 231, 8
   CONTROL "", 8327, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 76, 238, 16
   CONTROL "Unlock the user’s &account", 8328, BUTTON, BS_AUTOCHECKBOX | BS_LEFT | BS_TOP | BS_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 14, 96, 230, 10
   CONTROL "OK", 1, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 140, 118, 50, 14
   CONTROL "Cancel", 2, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 195, 118, 50, 14
}
 

(more…)

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Random Active Directory Notes #3

Last time I talked briefly about IDirectoryObject and IDirectorySearch, let’s go into a little more detail today.

IDirectoryObject is an Interface that we can use to query anything in Active Directory, users, groups, organizational units, containers and so on.

I thought the best explanation would be to build a very small sample project, so let’s do that!

First we need some units, so please add the following units to your uses clause:

  • ComObj (for EOleException and it calls CoInitialize for us)
  • JwaWindows for the proper Adsi declarations

Next declare the following types:

type
  // For Delphi < 2009 use WideString
  UString = {$IFDEF UNICODE}UnicodeString{$ELSE}WideString{$ENDIF};

  // Array of ADS_ATTR_INFO records
  TAdsAttrInfoArray = array[0..ANYSIZE_ARRAY-1] of ADS_ATTR_INFO;
  PAdsAttrInfoArray = ^TAdsAttrInfoArray;

(more…)

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Random Active Directory Notes #2

If you have ever used Adsi you have probably used the IADs interface or derived interfaces such as IADsUser or IADsGroup (maybe even without realising this).

What you need to know is that these interfaces were created to support scripting languages such as VBScript. The reason is that these scripting language have no support at all for structures such as ADSVALUE and don’t work with Pointers.

A typical use of IADs interface would look like this (in Delphi and using Jwa):

var
  IADsIntf: IADs;
  hr: HRESULT;
begin
  hr := AdsGetObject(
    ‘LDAP://CN=AUser,CN=Users,DC=domain,DC=local’, //lpszPathName
    IID_IADs, // riid
    Pointer(IADsIntf)); // ppObject

  if SUCCEEDED(hr) then

The IADs interfaces are fine when you are working with a single object but they are very, very slow, when working with many objects. I also find them a pain to work with as only a few AD attributes are present as properties. For other attributes you need to call the Get method which doesn’t always work, in which case you probably need to call the GetEx method. Even the GetEx method doesn’t always return the desired result as the property might not be in the Cache in which case we need to call the GetInfoEx method first and then Get or GetEx.

Active Directory has the nasty habit of failing when a an attribute is not set, so if you are reading a eg string attribute you probably expect an empty string but Active Directory returns a failure in such a case. And since Delphi declares Get(Ex) as SafeCall it will raise an Exception so you need to wrap it in try..except.

If we have obtained a value it will always be a variant that we probably need to convert to another type such as a string, datetime or an integer.

My results with implementing IADs interfaces in my Active Directory unit were bad: I wrote a test program that mimics Active Directory Users & Computer and enumerating a Container or OU with about 70 users takes 2-3 seconds. If you need to wait that long when expaning a Tree Node this in simply not acceptable. So I decided to completely drop the IADs interfaces and used the interfaces that are meant for higher level languages such as IDirectoryObject and IDirectorySearch. And guess what? Now my Delphi program, even when running in the debugger, is actually much faster than Active Directory Users & Computers!

To be fair to Microsoft, in the documentation of IDirectoryObject is the following note: The IDirectorySearch interface is a pure COM interface that provides a low overhead method that non-Automation clients can use to perform queries in the underlying directory.

In the next posts I will talk about IDirectoryObject and IDirectorySearch.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Random Active Directory Notes

I am working on an Customer Management Console that will present all adminstrative tasks that customers will need in their environment in a single console.

It will handle Active Directory, Terminal Server and Citrix, Printers and will offer specific Views and Reporting. For the Active Directory stuff I decided to create some classes that enabled me to work with AD in a more Delphi OOP way.

In a series of Blog Posts I will write about interesting things or just random notes that I made while creating this stuff. The intention is to publish the whole unit in the Jedi Security Library when it’s finished.

Well I hope you that you’ll find some things of interest ;-)

Part 1 is here .

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Random Active Directory Notes #1

If you are going to use the Active Directory Service Interface (ADSI) in Delphi, the first thing you will need is the typelibrary (TLB). This TLB is in the windows\system32 folder and has the name activeds.tlb.

We can import this tlb in Delphi (the procedure differs somewhat, depending on the Delphi version), but there are quite some problems with the resulting pas file of this import:

  • Ugly and non meaningfull names such as __MIDL___MIDL_itf_ads_0000_0000_001.
  • Record sizes are sometimes (read: usually) wrong due to alignment errors.
  • Some Interfaces have wrong declarations resulting in Access Violations or just hard to use (eg using var for input parameters).
  • Delphi works with Typed Pointer but since it has no clue on the proper name it uses PUserTypexx (eg PUserType1 = ^_ADS_CASEIGNORE_LIST). It’s hard to recognise later on what the real type is.

A version of the imported tlb is also in the Jedi Apilib (JwaAdsTLB) and basically it had the same errors. Because I was wondering how this would work in c++ I checked the SDK and found the header file Iads.h.

(more…)

VN:F [1.9.3_1094]
Rating: 9.0/10 (1 vote cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

I am writing a class that wraps Active Directory into Objects that live in an Objectlist, much like my Terminal Server class in the Jedi Windows Security Library.

One of the classes is TJwADUser that represents an Active Directory user with all kinds of properties. So while I was implementing them I stumbled upon the accountExpires attribute which is implemented as an 8 byte integer so I figured I could read it as Int64, cast this to TFileTime (FILETIME) and convert to TDateTime.

This raised an error however (EVariantTypeCastError with message ‘Could not convert variant of type (Dispatch) into type (Double)’.).

So I checked what kind of variant Active Directory returns and it is not the expected varInt64 but varDispatch.
It turns out that we need the IADsLargeInteger interface to obtain the correct values. The code below works for me:

function TJwADUser.GetExpirationDate: TDateTime;
var
  LargeInteger: IADsLargeInteger;
  ft: TFileTime;
  v: Variant;
begin
  if Get(‘accountExpires’, v) then
  begin
    LargeInteger := IDispatch(v) as IADsLargeInteger;
    ft.dwLowDateTime := LargeInteger.LowPart;
    ft.dwHighDateTime := LargeInteger.HighPart;
    if Int64(ft) = 0 then
      Result := 0
    else
      Result := FileTime2DateTime(ft)
  end
  else begin
    Result := 0;
  end;
end;

Notes: The Get function is a wrapper for IADs(User).Get(Ex) so you can ignore that and my function returns 0 when the value is empty or on read failure.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Most administrator will want to prevent normal users from opening Regedit and a command prompt. Usually this is done by activating the “Prevent access to registry editing tools” and “Prevent access to the command prompt” policy settings. They are located under User Configuration | Administrative Templates | System:

gpedit

Activating the policies will set the matching keys in the registry:

regkey

If we try to open regedit we are denied access:

regedit1

So how does this work? (more…)

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Microsoft has releaseed the Remote Server Administration Tools (RSAT) for Vista SP1. RSAT enables IT administrators to remotely manage roles and features in Windows Server 2008 from a computer running Windows Vista with SP1. It includes support for remote management of computers running either a Server Core installation or the full installation option of Windows Server 2008. It provides similar functionality to Windows Server 2003 Administration Tools Pack.

You can find RSAT here.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
convert this post to pdf.

Paypal Donation

Amount:
Website(Optional):


Categories


Archives


Views


Tags

bug Business Citrix datastore dsn error error 26009 Installation Java jre jvm LinkedIn Objects referall was returned SasLibEx script slow Switch Terminal Server TSAdmin TSAdminEx Unattended VBS Versions Vista Windows Vista WLAN WTSWaitSystemEvent wts_event_flush

Blogroll