End-user account info from Active Directory for Windows network login

Relevant links:

$SAMPLECODE$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19

loAdUser = ADUserInfo()

? "cn:", loAdUser.cn
? "department:", loAdUser.department
? "displayname:", loAdUser.displayName
? "fax:", loAdUser.facsimileTelephoneNumber
? "emailaddr:", loAdUser.mail
? "lastname:", loAdUser.sn
? "firstName:", loAdUser.givenName
? "telephone:", loAdUser.telephoneNumber
? "dn:", loAdUser.distinguishedName
? "upn:", loAdUser.userPrincipalName
? "title:", loAdUser.title

? "last logon (UTC):", ConvertADoffset2UtcTime(loAdUser.lastlogon)
? "account expires (UTC):", ConvertADoffset2UtcTime(loAdUser.accountexpires)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

* Retrieve ADUser info for Windows Login 
FUNCTION ADUserInfo
LPARAMETERS tcUserName, tcUserDomain
LOCAL lcUserName, lcCurrentUserName, lcCurrentUserDomain, lcUserDomain, loNameTrans, lcDN, loAdUser
#DEFINE ADS_NAME_INITTYPE_GC  3
#DEFINE ADS_NAME_TYPE_NT4 	3
#DEFINE ADS_NAME_TYPE_1779 	1

lcCurrentUserName = GETENV("UserName")
lcCurrentUserDomain = GETENV("UserDomain")

* If parameters are not supplied, use current user login info
lcUserName = EVL(tcUserName, lcCurrentUserName)
lcUserDomain = EVL(tcUserDomain, lcCurrentUserDomain)

* Use NameTranslate object to get DN based on Windows Login Name
loNameTrans = CREATEOBJECT("NameTranslate")					
loNameTrans.Init( ADS_NAME_INITTYPE_GC, "")
TRY
	loNameTrans.Set(ADS_NAME_TYPE_NT4, lcUserDomain + "\" + lcUserName)
	lcDN = loNameTrans.Get(ADS_NAME_TYPE_1779)
	loAdUser = GETOBJECT("LDAP://" + lcDN)
CATCH TO oExp WHEN oExp.Errorno = 1426
	loAdUser = Null
ENDTRY	

RETURN loAdUser

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

* 64-bit integer as a number 
FUNCTION ConvertADsLargeInteger(toADsLargeInteger)
RETURN toADsLargeInteger.HighPart * (2^32) + IIF(toADsLargeInteger.LowPart < 0, 2^32, 0) + toADsLargeInteger.LowPart

* UTC Time from AD offset.
FUNCTION ConvertADoffset2UtcTime(toADsLargeInteger)
LOCAL lnSecondsOffset
* Offset is from 1601-01-01 in 100 nanoseconds
lnSecondsOffset = INT(ConvertADsLargeInteger(toADsLargeInteger) / 10^7)
IF lnSecondsOffset > 265046774399 
	* The date will be bigger than > 9999-12-31 23:59:59
	lnSecondsOffset = NULL
ENDIF	

RETURN CAST(DATETIME(1601, 01, 01) + lnSecondsOffset AS datetime)

Comments

Thank you. This is very helpful!

Exactly what I needed for my company's email change.
Thanks Sergey!

Can you convert VB.NET code below in VFP 9.0?

Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean
Dim Success As Boolean = False
Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)
Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel
Try
Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
Success = Not (Results Is Nothing)
Catch
Success = False
End Try
Return Success
End Function

Check wwDotnetBridge from https://west-wind.com/wwdotnetbridge.aspx