Getting network details from Active Directory in VB script? - vbscript

There are needs when we want to populate user details from Active Directory. Sharing my code to access user details from AD.

Introduction
People often ask for querying active directory by passing network account name or email. There are many articles already available on this, and one might get confused. Here is simple working code to access user detail from active directory database-
Please note in order to access AD, you have to specify valid network account credentials in connection.
function GetADDetails(userId)
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.provider ="ADsDSOObject"
objConn.Properties("User ID") = "domain\userId" 'specify domain and
network account
objConn.Properties("Password") = "password" 'specify network password
objConn.Properties("Encrypt Password") = True
objConn.open "Active Directory Provider"
Set objCom = CreateObject("ADODB.Command")
Set objCom.ActiveConnection = objConn
strTarget="GC://abc.com" 'your domain name
objCom.CommandText ="select sn, givenName, sAMAccountName, name,mail,
telephoneNumber FROM '"+strTarget+"' where sAMAccountname='"+userId+"'"
Set objRS = objCom.Execute
If Not (objRS.EOF Or objRS.BOF) Then
GetADDetails=objRS.GetRows
Else
GetUserData = Null
End If
'Close objects and remove from memory
objRS.Close
objConn.Close
Set objRS = Nothing
Set objConn = Nothing
Set objCom = Nothing
end function

Related

Get Administrotor Object in windows in different language

I've a vbscript to authenticate an user credentials, one part of my code is
Set objLocalGroup = GetObject("WinNT://./Administrators, group")
now this code fail in Windows(German and French Version), after debugging, I think the problem is that, in German Version, the Group corresponding to English "Administrators" was named "Administratoren"..
Is there any generic way to get the Object?
Thanks.
The administrators group has a well-known SID, so something like this should work:
Set wmi = GetObject("winmgmts://./root/cimv2")
Set admins = wmi.Get("Win32_SID.SID='S-1-5-32-544'")
Set objLocalGroup = GetObject("WinNT://./" & admins.AccountName & ",group")
Another way would be getting the name from the Win32_Group class:
Set wmi = GetObject("winmgmts://./root/cimv2")
qry = "SELECT * FROM Win32_Group WHERE SID = 'S-1-5-32-544'"
For Each group In wmi.ExecQuery(qry)
Set objLocalGroup = GetObject("WinNT://./" & group.Name & ",group")
Next

Managing remote DACLs on fileshares: Win32_ACE to Win32_Share

Goal: Add a local user account share-level Read/Write permissions to an existing file share.
I'm hitting a roadblock in developing this. Apparently Microsoft wants you to add your user's ACE to the DACL and then back into the security descriptor of the share. (1). (No, NET SHARE /ADD is not available for existing shares, I was surprised.)
In theory that should be simple enough, but my main fear is doing it wrong and losing the existing share permissions (lots of network users, specific groups). This solution needs to scale to a few thousand shares. I'm developing the solution to output data about the existing DACL in case I need to back out. I should write code to interpret that log and be prepared to add them back en-masse should anything go wrong.
At the moment I'm using VBscript-- I feel PowerShell might be a bit stronger of an approach but VBscript/WMI is a known quantity.
Research:
(1) http://blogs.msdn.com/b/helloworld/archive/2008/07/22/editing-share-permission.aspx
Copy the existing ACEs to an array:
rc = shareSec.GetSecurityDescriptor(sd)
ReDim acl(UBound(sd.DACL)+1) '+1 for the new ACL we're going to add
For i = 0 To UBound(sd.DACL)
Set acl(i) = sd.DACL(i)
Next
Add the new ACE to that array:
Set acl(UBound(acl)) = NewACE(NewTrustee(username, domain), 2032127)
The functions NewTrustee() and NewACE() encapsulate the instructions for creating the trustee and the ACE. The number is the access mask for Full Control.
Create a new security descriptor and assign it to the share:
Set sd = wmi.Get("Win32_SecurityDescriptor").SpawnInstance_
sd.ControlFlags = flags
sd.DACL = acl
rc = shareSec.SetSecurityDescriptor(sd)
Check this page for a lot more detail information about security descriptors, trustees, ACLs and ACEs.
Full script:
Const FullControl = 2032127
' modify these variables according to your requirements:
computer = "."
share = "..."
username = "..."
domain = CreateObject("WScript.Network").UserDomain
Set wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!//" _
& computer & "/root/cimv2")
Set shareSec = GetObject("winmgmts:Win32_LogicalShareSecuritySetting.Name='" _
& share & "'")
Function NewTrustee(name, domain)
Dim trustee, account
Set trustee = wmi.Get("Win32_Trustee").SpawnInstance_
trustee.Name = name
trustee.Domain = domain
Set account = wmi.Get("Win32_UserAccount.Domain='" & domain & "',Name='" _
& name & "'")
trustee.Properties_.Item("SID") = wmi.Get("Win32_SID.SID='" & account.SID _
& "'").BinaryRepresentation
Set NewTrustee = trustee
End Function
Function NewACE(trustee, permissions)
Dim ace : Set ace = wmi.Get("Win32_Ace").SpawnInstance_
ace.Properties_.Item("AccessMask") = permissions
ace.Properties_.Item("AceFlags") = 3
ace.Properties_.Item("AceType") = 0
ace.Properties_.Item("Trustee") = trustee
Set NewACE = ace
End Function
' copy existing ACEs
rc = shareSec.GetSecurityDescriptor(sd)
flags = sd.ControlFlags
ReDim acl(UBound(sd.DACL)+1) '+1 for the new ACL we're going to add
For i = 0 To UBound(sd.DACL)
Set acl(i) = sd.DACL(i)
Next
Set sd = Nothing
' add new ACE
Set acl(UBound(acl)) = NewACE(NewTrustee(username, domain), FullControl)
' prepare new security descriptor
Set sd = wmi.Get("Win32_SecurityDescriptor").SpawnInstance_
sd.ControlFlags = flags
sd.DACL = acl
' assign new security descriptor
rc = shareSec.SetSecurityDescriptor(sd)

ADS user details - subdomain - from vbs file

I managed to get ADS users without specifying authentication details from my ADS domain(ex,mydomain.com). I used ADODB.Connection and ADODB.Command.
I also have sub-domains like test.mydomain.com. How to get user details from sub-domain, by specifying authentication details of a user belonging to test.mydomain.com .
You can query records from trusted domains by using their LDAP name as the search base. However, since the DC of the parent domain doesn't contain the information about objects in the child domain it will generate a referral. The ADODB.Command object won't automatically chase that referral, because the respective named property "Chase referrals" defaults to 0x00 (ADS_CHASE_REFERRALS_NEVER). You have to set the property to one of the following two values
ADS_CHASE_REFERRALS_SUBORDINATE (0x20)
ADS_CHASE_REFERRALS_ALWAYS (0x60)
to make your query follow the referral. Example:
base = "<LDAP://dc=test,dc=example,dc=org>"
filter = "(&(objectCategory=computer)(name=foo*))"
attr = "name,description"
scope = "subtree"
Set conn = CreateObject("ADODB.Connection")
conn.Provider = "ADsDSOObject"
conn.Open "Active Directory Provider"
Set cmd = CreateObject("ADODB.Command")
Set cmd.ActiveConnection = conn
cmd.CommandText = base & ";" & filter & ";" & attr & ";" & scope
cmd.Properties("Chase referrals") = &h60 ' <-- here
Set rs = cmd.Execute
I wrote a wrapper class (ADQuery) to encapsulate the boilerplate code for Active Directory queries (because I got fed up with writing it over and over again). With that you could simplify the above to something like this:
Set qry = New ADQuery
qry.SearchBase = "dc=test,dc=example,dc=org"
qry.Filter = "(&(objectCategory=computer)(name=foo*))"
qry.Attributes = Array("name", "description")
Set rs = qry.Execute
Either way you may still need to run the script on a DC, though.

Secure LDAP object manipulation with VBscript using alternate credentials

I'm aware of using ADsDSOobject with explicit credentials to connect to an AD object to read attributes, list members, etc. And the GetObject("LDAP//...") method for manipulating those objects (adding group members, changing properties, etc.), but is there a way to manipulate attributes and memberships with explicit credentials?
The first method I'm referring to is something like...
Set conn = Server.CreateObject("ADODB.Connection")
Set cmd = Server.CreateObject("ADODB.Command")
conn.Provider = "ADsDSOobject"
conn.Properties("User ID") = AD_Username
conn.Properties("Password") = AD_Password
conn.Properties("Encrypt Password") = True
conn.Open "Active Directory Provider"
Set cmd.ActiveConnection = conn
But none of the script examples that perform tasks like adding a user to a domain group can use this approach as far as I know. Is there a way to do that somehow?
In VBScript, very often, you are using ADSI to add user to group. Here is a sample code to add a user to a domain group
Set objUser = GetObject("LDAP://CN=jeffsmith,DC=fabrikam,DC=com")
Set objGroup = GetObject("LDAP://CN=group1,DC=fabrikam,DC=com")
objGroup.add(objUser.ADsPath)
It works fine but it's always using your current user credentails. It's because GetObject doesn't allow you to specify alternate credentials.
To specify another credentails, you need to replace GetObject by OpenDSObject
Const ADS_SECURE_AUTHENTICATION = 1
Set openDS = GetObject("LDAP:")
Set objUser = openDS.OpenDSObject("LDAP://CN=jeffsmith,DC=fabrikam,DC=com",
"username",
"password",
ADS_SECURE_AUTHENTICATION)
Set objGroup = openDS.OpenDSObject("LDAP://CN=group1,DC=fabrikam,DC=com",
"username",
"password",
ADS_SECURE_AUTHENTICATION)
objGroup.add(objUser.ADsPath)

How to connect to LDAP store with VB6

I’ve got a problem with Visual Basic (6) in combination with LDAP. When I try to connect to an LDAP store, I always get errors like ‘Bad Pathname’ or ‘Table does not exist’ (depending on what the code looks like).
This is the part of the code I wrote to connect:
path = "LDAP://xx.xxx.xxx.xxx:xxx/"
Logging.WriteToLogFile "Test1", logINFO
Set conn = CreateObject("ADODB.Connection")
conn.Provider = "ADsDSOObject"
conn.Properties("User ID") = "USER_ID"
conn.Properties("Password") = "PASSWORD"
conn.Properties("Encrypt Password") = True
conn.Properties("ADSI Flag") = 34
Logging.WriteToLogFile "Test2", logINFO
conn.Open "Active Directory Provider"
Logging.WriteToLogFile "Test3", logINFO
Set rs = conn.Execute("<" & path & "ou=Some,ou=Kindof,o=Searchbase>;(objectclass=*);name;subtree")
Logging.WriteToLogFile "Test4", logINFO
The logfile shows “Test1” , “Test2”, “Test3” and then “Table does not exist”, so it’s the line “Set rs = conn.Execute(…)” where things go wrong (pretty obvious…).
In my code, I try to connect in a secure way. I found out it has nothing to do with SSL/certificates though, because it’s also not possible to establish an anonymous unsecured connection. Funny thing is: I wrote a small test app in .NET in five minutes. With that app I was able to connect (anonymously) and read results from the LDAP store, no problems at all.
Does anyone have any experience with the combination LDAP and VB6 and maybe know what could be the problem? I googled and saw some example code snippets, but unfortunately none of them worked (same error messages as result). Thanks in advance!
I'm not sure how much help this will be, but I use this code to access Active Directory objects.
Set oinfo = New ADSystemInfo
sDomain = Split(oinfo.DomainDNSName, ".")
'-- Get Datasets from the Active Directory
'-- Connect to Active Directory in logged in domain
con.Open "Provider=ADsDSOObject;Encrypt Password=False;Integrated Security=SSPI;Data Source=ADSDSOObject;Mode=Read;Bind Flags=0;ADSI Flag=-2147483648"
'-- Query all serviceConnectionPoints in the Active Directory
'-- that contain the keyword "urn://tavis.net/TM/Database"
'-- and return the full path to the object
Set rst = con.Execute("<LDAP://DC=" & sDomain(0) & ",DC=" & sDomain(1) & ">;(&(objectCategory=serviceConnectionPoint)(keywords=urn://tavis.net/TM/Database));Name, AdsPath;subTree")
2 things:
The Open() method call takes additional parameters, server/username/password
The LDAP query you passed to Execute() should be:
"<" & path & "ou=Some/ou=Kindof/o=Searchbase>;(objectclass=*);name;subtree"

Resources