To get a list of all users in a Windows NT/2000 domain, we can use the NetUserEnum
API function.
Although the API provides several levels of
information associated with an user account, the user name is provided in the
USER_INFO_0 structure which is the lowest set of information
returned. The USER_INFO_2 returns a great deal more of
information pertaining to a specific user account.
A sample function for both level 0 and level 2 API calls is included below.
Please note that these are NT/2000 only API function.
Private Type USER_INFO_0
usri0_name As Long
End Type
Private Type USER_INFO_2
usri2_name As Long
usri2_password As Long
usri2_password_age As Long
usri2_priv As Long
usri2_home_dir As Long
usri2_comment As Long
usri2_flags As Long
usri2_script_path As Long
usri2_auth_flags As Long
usri2_full_name As Long
usri2_usr_comment As Long
usri2_parms As Long
usri2_workstations As Long
usri2_last_logon As Long
usri2_last_logoff As Long
usri2_acct_expires As Long
usri2_max_storage As Long
usri2_units_per_week As Long
usri2_logon_hours As Long
usri2_bad_pw_count As Long
usri2_num_logons As Long
usri2_logon_server As Long
usri2_country_code As Long
usri2_code_page As Long
End Type
Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Private Type TIME_ZONE_INFORMATION
Bias As Long
StandardName(0 To 63) As Byte
StandardDate As SYSTEMTIME
StandardBias As Long
DaylightName(0 To 63) As Byte
DaylightDate As SYSTEMTIME
DaylightBias As Long
End Type
Private Declare Function apiNetUserEnum _
Lib "netapi32.DLL" Alias "NetUserEnum" _
(ByVal servername As Long, _
ByVal level As Long, _
ByVal filter As Long, _
bufptr As Long, _
ByVal prefmaxlen As Long, _
entriesread As Long, _
totalentries As Long, _
resume_handle As Long) _
As Long
Private Declare Function apiNetAPIBufferFree _
Lib "netapi32.DLL" Alias "NetApiBufferFree" _
(ByVal buffer As Long) _
As Long
Private Declare Function apilstrlenW _
Lib "kernel32" Alias "lstrlenW" _
(ByVal lpString As Long) _
As Long
Private Declare Sub sapiCopyMem _
Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As Long)
Private Declare Function apiGetTZI Lib "kernel32" _
Alias "GetTimeZoneInformation" _
(lpTimeZoneInformation As TIME_ZONE_INFORMATION) _
As Long
Private Const FILTER_TEMP_DUPLICATE_ACCOUNT = &H1&
Private Const FILTER_NORMAL_ACCOUNT = &H2&
Private Const FILTER_INTERDOMAIN_TRUST_ACCOUNT = &H8&
Private Const FILTER_WORKSTATION_TRUST_ACCOUNT = &H10&
Private Const FILTER_SERVER_TRUST_ACCOUNT = &H20&
Private Const MAX_PREFERRED_LENGTH = -1&
Private Const NERR_SUCCESS = 0
Private Const ERROR_MORE_DATA = 234&
Private Const USER_PRIV_GUEST = 0&
Private Const USER_PRIV_USER = 1&
Private Const USER_PRIV_ADMIN = 2&
Private Const TIME_ZONE_ID_INVALID = &HFFFFFFFF
Private Const TIME_ZONE_ID_UNKNOWN = 0
Private Const TIME_ZONE_ID_STANDARD = 1
Private Const TIME_ZONE_ID_DAYLIGHT = 2
Private Const UF_SCRIPT = &H1
Private Const UF_ACCOUNTDISABLE = &H2
Private Const UF_HOMEDIR_REQUIRED = &H8
Private Const UF_LOCKOUT = &H10
Private Const UF_PASSWD_NOTREQD = &H20
Private Const UF_PASSWD_CANT_CHANGE = &H40
Private Const UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = &H80
Private Const UF_DONT_EXPIRE_PASSWD = &H10000
Private Const UF_MNS_LOGON_ACCOUNT = &H20000
Private Const UF_SMARTCARD_REQUIRED = &H40000
Private Const UF_TRUSTED_FOR_DELEGATION = &H80000
Private Const UF_NOT_DELEGATED = &H100000
Private Const UF_USE_DES_KEY_ONLY = &H200000
Private Const UF_DONT_REQUIRE_PREAUTH = &H400000
Private Const UF_TEMP_DUPLICATE_ACCOUNT = &H100
Private Const UF_NORMAL_ACCOUNT = &H200
Private Const UF_INTERDOMAIN_TRUST_ACCOUNT = &H800
Private Const UF_WORKSTATION_TRUST_ACCOUNT = &H1000
Private Const UF_SERVER_TRUST_ACCOUNT = &H2000
Function fEnumDomainUsers_Level2( _
Optional strServerName As String) _
As Boolean
On Error GoTo ErrHandler
Dim abytServerName() As Byte
Dim pBuf As Long
Dim pTmpBuf As USER_INFO_2
Dim dwLevel As Long
Dim dwPrefMaxLen As Long
Dim dwEntriesRead As Long
Dim dwTotalEntries As Long
Dim dwResumeHandle As Long
Dim i As Long
Dim dwTotalCount As Long
Dim nStatus As Long
dwPrefMaxLen = MAX_PREFERRED_LENGTH
abytServerName = strServerName & vbNullChar
dwLevel = 2
Do
nStatus = apiNetUserEnum(VarPtr(abytServerName(0)), _
dwLevel, _
FILTER_NORMAL_ACCOUNT, _
pBuf, _
dwPrefMaxLen, _
dwEntriesRead, _
dwTotalEntries, _
dwResumeHandle)
If ((nStatus = NERR_SUCCESS) Or (nStatus = ERROR_MORE_DATA)) Then
For i = 0 To dwEntriesRead - 1
Call sapiCopyMem( _
pTmpBuf, _
ByVal (pBuf + (i * 96)), _
Len(pTmpBuf))
With pTmpBuf
Debug.Print "Name : ", fStrFromPtrW(.usri2_name)
Debug.Print "Account Info: "
Call sPrintAccountInfo(.usri2_flags)
Debug.Print "Number of seconds since the " _
& "password was last changed: ", .usri2_password_age
Debug.Print "Level of Privilege: ",
Select Case .usri2_priv
Case USER_PRIV_GUEST
Debug.Print "Guest"
Case USER_PRIV_USER
Debug.Print "User"
Case USER_PRIV_ADMIN
Debug.Print "Admin"
End Select
Debug.Print "Home Directory: ", fStrFromPtrW(.usri2_home_dir)
Debug.Print "Comment: ", fStrFromPtrW(.usri2_comment)
Debug.Print "Script Path: ", fStrFromPtrW(.usri2_script_path)
Debug.Print "Full Name: ", fStrFromPtrW(.usri2_full_name)
Debug.Print "User Comment: ", fStrFromPtrW(.usri2_usr_comment)
Debug.Print "Params for Apps: ", fStrFromPtrW(.usri2_parms)
Debug.Print "Workstations from which user can log on: ", _
fStrFromPtrW(.usri2_workstations)
Debug.Print "Last Logon occurred at: ", fGetTime(.usri2_last_logon)
Debug.Print "Last Logoff occurred at: ", fGetTime(.usri2_last_logoff)
Debug.Print "Account Expires on: ", fGetTime(.usri2_acct_expires)
Debug.Print "Max Disk Space allotted: ", .usri2_max_storage
Debug.Print "Units per week: ", .usri2_units_per_week
Debug.Print "Logon Hours: ", .usri2_logon_hours
Debug.Print "Bad password count: ", .usri2_bad_pw_count
Debug.Print "Number of successful logons: ", .usri2_num_logons
Debug.Print "Logon Server: ", fStrFromPtrW(.usri2_logon_server)
Debug.Print "Country Code: ", .usri2_country_code
Debug.Print "Code Page: ", .usri2_code_page
End With
dwTotalCount = dwTotalCount + 1
Debug.Print "--------------------------------"
Next
End If
Call apiNetAPIBufferFree(pBuf)
pBuf = 0
Loop While (nStatus = ERROR_MORE_DATA)
If Not (pBuf = 0) Then Call apiNetAPIBufferFree(pBuf)
fEnumDomainUsers_Level2 = True
ExitHere:
Exit Function
ErrHandler:
fEnumDomainUsers_Level2 = False
Resume ExitHere
End Function
Function fEnumDomainUsers( _
Optional strServerName As String) _
As Boolean
On Error GoTo ErrHandler
Dim abytServerName() As Byte
Dim pBuf As Long
Dim pTmpBuf As USER_INFO_0
Dim dwLevel As Long
Dim dwPrefMaxLen As Long
Dim dwEntriesRead As Long
Dim dwTotalEntries As Long
Dim dwResumeHandle As Long
Dim i As Long
Dim dwTotalCount As Long
Dim nStatus As Long
dwPrefMaxLen = MAX_PREFERRED_LENGTH
abytServerName = strServerName & vbNullChar
dwLevel = 0
Do
'only global users
nStatus = apiNetUserEnum(VarPtr(abytServerName(0)), _
dwLevel, _
FILTER_NORMAL_ACCOUNT, _
pBuf, _
dwPrefMaxLen, _
dwEntriesRead, _
dwTotalEntries, _
dwResumeHandle)
If ((nStatus = NERR_SUCCESS) Or (nStatus = ERROR_MORE_DATA)) Then
For i = 0 To dwEntriesRead - 1
Call sapiCopyMem( _
pTmpBuf, _
ByVal (pBuf + (i * 4)), _
Len(pTmpBuf))
Debug.Print fStrFromPtrW(pTmpBuf.usri0_name)
dwTotalCount = dwTotalCount + 1
Next
End If
Call apiNetAPIBufferFree(pBuf)
pBuf = 0
Loop While (nStatus = ERROR_MORE_DATA)
If Not (pBuf = 0) Then Call apiNetAPIBufferFree(pBuf)
fEnumDomainUsers = True
ExitHere:
Exit Function
ErrHandler:
fEnumDomainUsers = False
Resume ExitHere
End Function
Private Sub sPrintAccountInfo(lngFlags As Long)
If lngFlags And UF_ACCOUNTDISABLE Then
Debug.Print Space$(5), "Account is disabled."
End If
If lngFlags And UF_HOMEDIR_REQUIRED Then
Debug.Print Space$(5), "Home Direcotory is required."
End If
If lngFlags And UF_PASSWD_NOTREQD Then
Debug.Print Space$(5), "No password is required."
End If
If lngFlags And UF_PASSWD_CANT_CHANGE Then
Debug.Print Space$(5), "The user cannot change the password."
End If
If lngFlags And UF_LOCKOUT Then
Debug.Print Space$(5), "The account is currently locked out."
End If
If lngFlags And UF_DONT_EXPIRE_PASSWD Then
Debug.Print Space$(5), "The password should never expire on the account."
End If
If lngFlags And UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED Then
Debug.Print Space$(5), "The User 's password is stored " _
& "under reversible encryption in the Active Directory."
End If
If lngFlags And UF_NOT_DELEGATED Then
Debug.Print Space$(5), "Sensitive account; other " _
& "users cannot act as delegates of this user account."
End If
If lngFlags And UF_SMARTCARD_REQUIRED Then
Debug.Print Space$(5), "Smart card is required to log on."
End If
If lngFlags And UF_DONT_REQUIRE_PREAUTH Then
Debug.Print Space$(5), "This account does not require " _
& "Kerberos preauthentication for logon."
End If
If lngFlags And UF_TRUSTED_FOR_DELEGATION Then
Debug.Print Space$(5), "The account is enabled for delegation."
End If
If lngFlags And UF_SCRIPT Then
Debug.Print Space$(5), "The logon script executed. "
End If
If lngFlags And UF_NORMAL_ACCOUNT Then
Debug.Print Space$(5), "This is a default account " _
& "type that represents a typical user."
End If
If lngFlags And UF_TEMP_DUPLICATE_ACCOUNT Then
Debug.Print Space$(5), "This is an account for users " _
& "whose primary account is in another domain. "
End If
If lngFlags And UF_WORKSTATION_TRUST_ACCOUNT Then
Debug.Print Space$(5), "This is a computer account for a " _
& "Windows NT/Windows 2000 workstation or Windows " _
& "NT/Windows 2000 server that is a member of this domain."
End If
If lngFlags And UF_SERVER_TRUST_ACCOUNT Then
Debug.Print Space$(5), "This is a computer account for a " _
& "backup domain controller that is a member of this domain."
End If
If lngFlags And UF_INTERDOMAIN_TRUST_ACCOUNT Then
Debug.Print Space$(5), "This is a permit to trust account for " _
& " a domain that trusts other domains."
End If
End Sub
Private Function fGetTime(ByVal lngSeconds As Long) As Variant
Dim lpTZI As TIME_ZONE_INFORMATION
Dim lngRet As Long
Const START_DATE = "01/01/1970 00:00:00"
lngRet = apiGetTZI(lpTZI)
If Not lngRet = TIME_ZONE_ID_INVALID Then
With lpTZI
fGetTime = DateAdd("s", lngSeconds - (.Bias * 60) _
- (.DaylightBias * 60), _
CDate(START_DATE))
End With
End If
End Function
Private Function fStrFromPtrW(pBuf As Long) As String
Dim lngLen As Long
Dim abytBuf() As Byte
lngLen = apilstrlenW(pBuf) * 2
If lngLen Then
ReDim abytBuf(lngLen)
Call sapiCopyMem( _
abytBuf(0), _
ByVal pBuf, _
lngLen)
fStrFromPtrW = abytBuf
End If
End Function
|