Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Need to check if an AD group exists 1

Status
Not open for further replies.

kmcferrin

MIS
Jul 14, 2003
2,938
US
I have a script that creates domain local and global groups based off of server names in multiple domains in a forest. It works fine, except that if it tries to create a group that already exists it will error out. I just need to verify that the group doesn't exist before it does the "put" to create the group. This is what I have now:

Code:
For Each strComputer in arrComputers

    '   Create Global group in AD
  	Set objContainer = GetObject("LDAP://" & strGlobalContainer)
	strAdminGlobalName = strComputer & "_Admin_Access_AMR_GG"
	Set objGroupGG = objContainer.Create("group", "cn=" & strAdminGlobalName)
	objGroupGG.Put "sAMAccountName", strAdminGlobalName
	objGroupGG.Put "groupType", ADS_GROUP_TYPE_Global_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED
	objGroupGG.SetInfo
    
    '   Create Domain Local group in AD
  	Set objContainer = GetObject("LDAP://" & strDomainLocalContainer & "," & objRootDSE.DistinguishedName)
	strAdminDomainLocalName = strComputer & "_Admin_Access_AMR_DL"
	Set objGroupDL = objContainer.Create("group", "cn=" & strAdminDomainLocalName)
	objGroupDL.Put "sAMAccountName", strAdminDomainLocalName
	objGroupDL.Put "groupType", ADS_GROUP_TYPE_LOCAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED
	objGroupDL.SetInfo
    
    If intCrossForest = 1 Then
        '   Get SID of Global Group from domain.local
        intUserSID = fnGet_HexString(objGroupGG.ObjectSID)

        '   Make Global group a member of the Domain Local group.
        objGroupDL.Add("LDAP://<SID=" & intUserSID & ">")    
    Else
        '   Make Global group a member of the Domain Local group.
        objGroupDL.Add(objGroupGG.ADsPath)
    End If

    '   Tries to ping server and add Domain Local group to the Local Administrators group on the server
    If IsPingable(strComputer, "", "") Then
        Wscript.Echo strComputer & " appears to be online, attempting to add Domain Local group to server local Administrators group."
        Set objServerLocalAdminGroup = GetObject("WinNT://" & strComputer & "/Administrators")
        Set objUser = GetObject("WinNT://" & strAdminDomainLocalName & "@" & strDomain)
        objServerLocalAdminGroup.Add(objUser.ADsPath)
    Else
        strOffline = strOffline & vbCr & strComputer
    End If

Next

I'm sure I can create a function to do a query to AD to return all of the groups with the name that I am checking for (strAdmingGlobalName or strAdminDomainLocalName), and if the collection returned is empty then I know that it doesn't exist. But is there a more elegant way to do this in the code above?
 
Eh...I got impatient and went the function route.

Code:
Function GroupExists(strGroup)

    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCommand.ActiveConnection = objConnection
        Set objRootLDAP = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootLDAP.Get("DefaultNamingContext")

    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

    objCommand.CommandText = _
        "SELECT Name FROM 'LDAP://" & strDNSDomain & "' WHERE objectCategory='group' " & "AND Name='" & strGroup & "'"

    Set objRecordSet = objCommand.Execute

    objRecordSet.MoveFirst
    Do Until objRecordSet.EOF
        If objRecordSet.Fields("Name").Value = strGroup Then
            GroupExists = True
        Else
            GroupExists = False
        End If
        objRecordSet.MoveNext
    Loop

End Function
 
But that didn't work, so I tried this instead:

Code:
    Set objRecordSet = objCommand.Execute

    If objRecordSet.BOF Then
        GroupExists = False
    Else
        GroupExists = True
    End If

And that worked. If I keep talking to myself people are going to think that I'm crazy.
 
Not crazy...if anything...maybe helpful to those who are learning...to see someone's thought and troubleshooting process.

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
So here's a variation on the problem above. Before I try to add the Global Group to the membership of the Domain Local group, I want to check to see if it is already a member. I have some code that can enumerate group members that I got from Technet.

Code:
Set objGroup = GetObject("LDAP://CN=Accountants,OU=Finance,DC=fabrikam,DC=com")
For Each objMember in objGroup.Member
    Wscript.Echo objMember
Next

When I try to modify it for my example above I get problems.

Code:
    Set objGroup = GetObject("LDAP://CN=" & strAdminDomainLocalName & "," & strDomainLocalContainer & "," & objRootDSE.DistinguishedName)
    Wscript.Echo objGroup.Member
    For Each objMember in objGroup.Member
        Wscript.Echo objMember
    Next

The "Wscript.Echo objGroup.Member" was added for troubleshooting. Without it, I kept getting an error on the "For Each" line indicating that the object is not a collection. OK, after beating my head against the wall it occurred to me that was correct, it wasn't a collection because the group only had one member. Doh! I learned today that a collection with a single member isn't a collection in VBScript. Which made me wonder what it would return if there were no members. The answer? the "Wscript.Echo objGroup.Member" doesn't do anything at all and I still get the "not a collection" issue.

So I added the "Wscript.Echo objGroup.Member" line to test that theory, and it echoes back the correct group name, but then bombs out at the "not a collection" point. So then I added a second member to the group, and it would bomb out on the "Wscript.Echo objGroup.Member" line, but once that line was commented out the "Fore Each" line worked as expected.

So the whole point of this is to verify whether the Global Group is a member of the Domain Local group, as I said. In theory (aka, according to our current design), the Domain Local group should only have one member and it should be the Global Group. So I could skip the "For Each" stuff. But theory and practice rarely mesh seamlessly, so I would really like to do a proper check by enumerating the group members and comparing them to the name of the Global Group. Logically, what is the best way to do this if there is the possibility that the group could have a single member, no members, or multiple members? Is there a property of AD groups that lists a count of members or something?
 
Try WScript.Echo objGroup.Member.Count ...if I remember correctly this will give you the count and then you can proceed accordingly depending on the count returned

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
That didn't work, but I did find inspiration in this post:


Which led to this simple function:

Code:
Function IsVariant(objGroup)

    IsVariant = InStr(1, TypeName(objGroup), "Variant", vbTextCompare)

End Function

As it turns out, it would return either a string or a variant, depending on whether there was just one member or multiple members. If it has no members it returns nothing, which probably should just be a Null check.
 
OK, not a Null. It returns the type of "Empty". At any rate, problem solved.
 
Just for the academics of it, I think your function should be OK, but where you are probably getting tripped up is on the actual name. Force the comparison in all lower or upper case.

Code:
Do Until objRecordSet.EOF
        If lcase(objRecordSet.Fields("Name").Value) = lcase(strGroup) Then
            GroupExists = True
        Else
            GroupExists = False
        End If
        objRecordSet.MoveNext
    Loop

I hope you find this post helpful.

Regards,

Mark

Check out my scripting solutions at
Work SMARTER not HARDER. The Spider's Parlor's Admin Script Pack is a collection of Administrative scripts designed to make IT Administration easier! Save time, get more work done, get the Admin Script Pack.
 
Good eye. I did in fact run into that problem later on and shifted it all to lower case.
 
OK, I'm back to having issues with this. I'm not sure if I missed a step in testing, or if something in the environment has changed that is causing problems. For some reason, my function to check if a group exists doesn't seem to work anymore.

This is what I have:

Code:
Function GroupExists(strGroup)

    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCommand.ActiveConnection = objConnection
    Set objRootLDAP = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootLDAP.Get("DefaultNamingContext")

    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

    objCommand.CommandText = _
        "SELECT Name FROM 'LDAP://" & strDNSDomain & "' WHERE objectCategory='group' " & "AND name='" & strGroup & "'"
    Wscript.Echo "Executing query:  " & objCommand.CommandText
    
    Set objRecordSet = objCommand.Execute
    
    Wscript.Echo TypeName(objRecordSet)
    
    Do Until objRecordSet.EOF
        Wscript.Echo "I got here (do Until)"
        Wscript.Echo objRecordSet.Fields("Name").Value
        If lcase(objRecordSet.Fields("Name").Value) = lcase(strGroup) Then
            GroupExists = True
        Else
            GroupExists = False
        End If
        objRecordSet.MoveNext
    Loop    
    'If objRecordSet.BOF Then
    '    GroupExists = False
    'Else
    '    GroupExists = True
    'End If
    ' Wscript.Echo "GroupExists = " & GroupExists

End Function

There are some extra echoes in there for troubleshooting purposes. The bits at the end were remarked out from a previous attempt.

When I run the script, the query that it generates is:

Code:
SELECT Name FROM 'LDAP://DC=domain,DC=local' WHERE objectCategory
='group' AND name='name_of_group'

Obviously the "domain" and "name_of_group" have been changed to protect the innocent, but when the script runs it does generate the correct data for those fields.

When I run the script it never returns that the group exists, even if it does. The script appears to get to the "Do Until objRecordSet.EOF" line and is already at .EOF (I'm guessing on that part) and goes directly to attempting to create the group. That's my assumption based on the fact that I never get the "I got here (do until)" message.
 
Use On Error Resume Next to allow the errors to happen when creating the group. You can then check for the erorr number to determine what happened:

Code:
If Err.number = 0 Then
	WScript.Echo "Group was created")
Else If Err.number = "-2147019886" Then
	WScript.echo "Group already exists"
    Else 
	    WScript.echo "Error creating group " & Err.Number & " " & Err.Description
    End If
End If

I hope you find this post helpful.

Regards,

Mark

Check out my scripting solutions at
Work SMARTER not HARDER. The Spider's Parlor's Admin Script Pack is a collection of Administrative scripts designed to make IT Administration easier! Save time, get more work done, get the Admin Script Pack.
 
On my machine your Function worked once I added

Const ADS_SCOPE_SUBTREE = 2

You may have that globally defined in your script in which case...disregard this post.

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
Doh!

You got it dm4ever. Somehow that line must have been deleted, because I looked over previous versions of the script and it was present.

Thanks!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top