Showing posts with label AD. Show all posts
Showing posts with label AD. Show all posts
I was recently working on a single domain which contained a lot of nested security groups (ie one group was a member of another, which in turn was a member of another etc.).
This kind of model can be useful to place a user account in one security group and automatically belong to many. However this can be a nightmare to diagnose if something goes wrong!
So here's a script I've had in my box of tricks for a while that should help. It outputs a list of users and all their group memberships (including the nested ones).
'==== SETTINGS ====================

' start ad path for user list
strOU = "OU=Site01,OU=Staff"


'==================================
If Right(LCase(WScript.FullName), 11) = "wscript.exe" Then
      Set objShell = CreateObject("WScript.Shell")
      objShell.Run "cscript """ & WScript.ScriptFullName & """", 1, False
      Set objShell = Nothing
      WScript.Quit
End If



Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection

 ' Search entire Active Directory domain.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

If Right(strOU, 1) <> "," Then strOU = strOU & ","
strBase = ""

strFilter = "(&(objectCategory=person)(objectClass=user))"

' Comma delimited list of attribute values to retrieve.
strAttributes = "ADsPath"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False

' Run the query.
Set adoRecordset = adoCommand.Execute


' Enumerate the resulting recordset.
Do Until adoRecordset.EOF
      WScript.Echo ""
      WScript.Echo "Proccessing: " & adoRecordset.Fields("ADsPath").Value

    ' Retrieve values and display.
      Set objUser = GetObject(adoRecordset.Fields("ADsPath").Value)

      strResults = ""
      strGroups = ""
     
      intLevel = 0
     
      GetMemberOfNames objUser, intLevel
     
      strResults = Replace(objUser.Name, "CN=", "") & " is a member of: "
      arrGroups = Split(strGroups, VbCrLf)
      For intCount = LBound(arrGroups) To UBound(arrGroups)
            If strResults = "" Then
                  strResults = arrGroups(intCount)
            Else
                  strResults = strResults & VbCrLf & arrGroups(intCount)
            End If
      Next

      Set objUser = Nothing

      WScript.Echo ""
      WScript.Echo strResults

      adoRecordset.MoveNext
Loop

' Clean up.
adoRecordset.Close
Set adoRecordset = Nothing

adoConnection.Close

MsgBox "Done. Please see text file " & strOutputFile


'==== Sub's and Functions =========

Sub GetMemberOfNames(objObjectToCheck, intLevel)
      ' This function can get caught in a loop if there is a circular
      ' group membership.  There is a method of using a Dictionary object
      ' here: http://www.rlmueller.net/MemberOf.htm
      ' which checks if the group has been used before.
     
      intLevel = intLevel + 1
      ' Retrieve ALL of the user groups that a user is a member of
      On Error Resume Next
      objMemberOf = objObjectToCheck.GetEx("MemberOf")
      If Err.Number = 0 Then
            On Error GoTo 0
            For Each objGroup in objMemberOf
                  strGroupName = Left(Mid(objGroup, InStr(objGroup, "CN=") + 3),InStr(Mid(objGroup, InStr(objGroup, "CN=") + 3), ",") - 1)
                  If strGroups = "" Then
                        strGroups = String(intLevel, chr(9)) & strGroupName
                  Else
                        strGroups = strGroups & VbCrLf & String(intLevel, chr(9)) & "o " & strGroupName
                  End If
                  Set objNextGroup = GetObject("LDAP://" & objGroup)
                  GetMemberOfNames objNextGroup, intLevel
            Next
            intLevel = intLevel - 1
      Else
            intLevel = intLevel - 1
            Err.Clear
            On Error GoTo 0
      End If
End Sub

NB: Usually I stick some comments at the top of code so I know the source. I've had this so long that really can't remember if I wrote this or modified someone else's code. So if the above looks familiar, drop me an email and I'll give you credit!


Sitting on an old Exchange 2003 server the other day, I needed a quick list of all the email addresses (including aliases). Being a bit old school the easiest thing for me to do was slap together a batch file to give me the answer. So to save me (and anyone else) the effort if I ever have to do it again, here it is:


@echo Off
ldifde -f %TEMP%\ldifde-dump.txt -l proxyaddresses
find "proxyAddresses: " < %TEMP%\ldifde-dump.txt > %TEMP%\ldifde-dump.filter1.txt
find "@" < %TEMP%\ldifde-dump.filter1.txt > %TEMP%\email-addresses.txt
del %TEMP%\ldifde-dump.txt
del %TEMP%\ldifde-dump.filter1.txt
notepad %TEMP%\email-addresses.txt
Using Microsoft's Orca tool to create an MST to work alongside the WPKGSetup.msi is a complete faff especially considering the end goal is rolling out a system that

will handle package management and rollout. Instead why not leverage WPKG to install it's own client?
The major advantage of doing this is that it allows you to upgrade and change WPKG Client parameters in the future using WPKG itself.

So this is how you do it:

First create a WPKG-Client package like this:

<package
   id="gplwpkgclient"
   name="WPKG Client 1.3.9"
   revision="2011.11.05.00"
   reboot="false"
   priority="99999">
 
 <!-- because the client hasn't been installed yet we cannot use the SOFTWARE parameter for paths -->
 <variable name="PKG_PATH" value="\\myserver\myshare\software\Components\gpl.wpkg.client.1.3.9" />
 
 <check type="uninstall" condition="exists" path="WPKG" />
 <check type="file" condition="versionequalto" path="%PROGRAMFILES%\wpkg\wpkginst.exe" value="1.0.0.18" />
 
 
   <install cmd='msiexec /i "%PKG_PATH%\WPKG Client 1.3.9-x32.msi" /qn SETTINGSFILE="%PKG_PATH%\settings.xml"' />
 
   <upgrade cmd='msiexec /i "%PKG_PATH%\WPKG Client 1.3.9-x32.msi" /qn SETTINGSFILE="%PKG_PATH%\settings.xml"' />
 
   <remove cmd='MsiExec /x{08DF8731-5B69-4709-979A-CC08E49D7686} /qn' />
 
</package>
Then in Active Directory, create a new Group Policy object with the following setting:
Computer Configuration → Windows Settings → Scripts(startup/shutdown) → Startup
Script: \\myserver\myshare\wpkg.js
Parameters: /install:gplwpkgclient /quiet

Job done!

The startup script will get WPKG to check if the latest version of the client has been installed every time the PC boots up but will only go through the installation process if no version exists or the current version installed does not match the revision number on the local PC's xml file.

And yes before you ask, I've added this to the wiki at www.wpkg.org.