Monday, April 20, 2009
0 comments

Active Directory: E-mail Notification for Newly Added Users and Computers

11:24 AM

Recently, someone asked if there was a way to be notified when servers have been added to an Active Directory domain. I looked around the Internet and it seems there's not a direct way to do this without some large software package. So in lieu of having an instant notification, I created a script that tallies up newly added user and computer accounts and emails the admin with all the info. This script is initially setup to be run once a day, but you can modify to whatever frequency you want.

I really expected this to take at most a couple hours to write but parsing through all the data turned out to take a heckofa lot of time. From converting the desired comparison date to UTC to parsing the AD attribute memberOf, I spent a good day working on this. I learned a lot, though and found this page which details the AD schema to be very helpful.

If you need anything more than this, you may want to consider an enterprise-type administration package such as Microsoft's MOM.

ADAddedUsersNComputers.vbs

'****************************************************************************
' This script created by Chrissy LeMaire (clemaire@gmail.com)
' Website: http://netnerds.net/
'
' ADAddedUsersNComputers.vbs
'
' This script Checks AD for any additions made to Users or Computers
' in the past 24 hours. The time interval to check can be changed below.
'
' NO WARRANTIES, USE THIS AT YOUR OWN RISK, etc.
'*****************************************************************************

'Please modify these four settings
strSMTPServer = "myexchangeserver"
strEmailFrom = "Administrator "
strEmailTo = "Administrator "

strTimeInUTC = CompareDateUTCConvert("h",-24) 'This is the same syntax as dateAdd(). The example will get new users/computers added in the past 24 hours.

'Unless you want to change the domain to check or the format of the emailed info, nothing below really needs to be modified.
On Error Resume Next
numPersonCount = 0
numComputerCount = 0

Set objAdRootDSE = GetObject("LDAP://RootDSE")
Set objRS = CreateObject("adodb.recordset")
varConfigNC = objAdRootDSE.Get("defaultNamingContext")
strConnstring = "Provider=ADsDSOObject"
strWQL = "SELECT ADsPath FROM 'LDAP://" & varConfigNC & "' WHERE createTimeStamp > '" & strTimeInUTC & "' and (objectCategory = 'Person' or objectCategory = 'Computer')"

objRS.Open strWQL, strConnstring
Do until objRS.eof
Set objADUserOrComputer = GetObject(objRS.Fields.Item(0))
strObjectCategory = ParseDN(objADUserOrComputer.objectCategory)

Select Case strObjectCategory
Case "Person"
numPersonCount = numPersonCount + 1
If Len(objADUserOrComputer.displayName) > 0 Then strUserMsg = strUserMsg & vbCrLf & "displayName = " & objADUserOrComputer.displayName
'strUserMsg = strUserMsg & vbCrLf & "distinguishedName = " & objADUserOrComputer.distinguishedName
strUserMsg = strUserMsg & vbCrLf & "sAMAccountName = " & objADUserOrComputer.sAMAccountName
strUserMsg = strUserMsg & vbCrLf & "sAMAccountType = " & SAMAccountTypetoName(objADUserOrComputer.sAMAccountType)
strUserMsg = strUserMsg & vbCrLf & "whenChanged = " & objADUserOrComputer.whenChanged
strUserMsg = strUserMsg & vbCrLf & "whenCreated = " & objADUserOrComputer.whenCreated
strUserGroups = ParseMemberOf(objADUserOrComputer.memberOf,objADUserOrComputer.PrimaryGroupID)
strUserMsg = strUserMsg & vbCrLf & "Member Of: " & strUserGroups
If Len(objADUserOrComputer.userPrincipalName) > 0 Then strUserMsg = strUserMsg & vbCrLf & "userPrincipalName = " & objADUserOrComputer.userPrincipalName
strUserMsg = strUserMsg & vbCrLf
Case "Computer"
numComputerCount = numComputerCount + 1
strCompMsg = strCompMsg & vbCrLf & "dNSHostName = " & objADUserOrComputer.dNSHostName
strCompMsg = strCompMsg & vbCrLf & "isCriticalSystemObject = " & objADUserOrComputer.isCriticalSystemObject
strCompMsg = strCompMsg & vbCrLf & "operatingSystem = " & objADUserOrComputer.operatingSystem
strCompMsg = strCompMsg & vbCrLf & "operatingSystemServicePack = " & objADUserOrComputer.operatingSystemServicePack
strCompMsg = strCompMsg & vbCrLf & "operatingSystemVersion = " & objADUserOrComputer.operatingSystemVersion
If InStr(objADUserOrComputer.rIDSetReferences,"Domain Controller") > 0 Then strCompMsg = strCompMsg & vbCrLf & "Domain Controller = Yes"
If Len(objADUserOrComputer.description) > 0 Then strCompMsg = strCompMsg & vbCrLf & "description = " & objADUserOrComputer.description
If Len(objADUserOrComputer.machineRole) > 0 Then strCompMsg = strCompMsg & vbCrLf & "machineRole = " & objADUserOrComputer.machineRole
If Len(objADUserOrComputer.physicalLocationObject) > 0 Then strCompMsg = strCompMsg & vbCrLf & "physicalLocationObject = " & ParseDN(objADUserOrComputer.physicalLocationObject)
strCompMsg = strCompMsg & vbCrLf
End Select
objRS.movenext
Set objADUserOrComputer = Nothing
Loop
objRS.close
Set objRS = Nothing
Set objAdRootDSE = Nothing

If Len(strUserMsg) > 0 Then strEmailMessage = strEmailMessage & "--------- USERS ---------" & vbCrLf & strUserMsg & vbCrLf
If Len(strCompMsg) > 0 Then strEmailMessage = strEmailMessage & "--------- COMPUTERS ---------" & vbCrLf & strCompMsg
If Len(strUserMsg) = 0 And Len(strCompMsg) = 0 Then strEmailMessage = "No users or computers have been added in the last 24 hours."

Set objCDO = CreateObject("CDO.Message")
objCDO.Subject = "Users Added: " & numPersonCount & ". Computers Added: " & numComputerCount & "."
objCDO.From = strEmailFrom
objCDO.To = strEmailTo
objCDO.TextBody = strEmailMessage
objCDO.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2 'cdoSendUsingPort (1 = local, 3 = Exchange)
objCDO.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSMTPServer
objCDO.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objCDO.Configuration.Fields.Update
objCDO.Send
set objCDO = Nothing

Function CompareDateUTCConvert(dateAddInterval,compareNumber)
'Wow, this is a lil complex. So createTimestamp is in UTC format.
'So first we grab your machine's time bias and then apply it.
'Next, we adjust the date to the one you specified above (now()-24hours by default)
'Finally, we parse the final date to UTC format ie. 20070207032200.0Z

Set objSWbemServices = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\.\root\cimv2")
Set colTimeZone = objSWbemServices.ExecQuery("SELECT * FROM Win32_TimeZone")
For Each objTimeZone in colTimeZone
strBias = objTimeZone.Bias
Next
Set colTimeZone = Nothing
Set objSWbemServices = Nothing
strCompareDate = dateAdd(dateAddInterval,compareNumber,now())
strUTCCompare = DateAdd("n",strBias*(-1),strCompareDate)
CurrentUTC = Year(strUTCCompare) & Right("0" & Month(strUTCCompare),2) & Right("0" & Day(strUTCCompare),2)
CurrentUTC = CurrentUTC & Right("0" & Hour(strUTCCompare),2) & Right("0" & Minute(strUTCCompare),2) & Right("0" & Second(strUTCCompare),2) & ".0Z"
CompareDateUTCConvert = CurrentUTC
End Function

Function ParseDN(strDN)
'Take a DN and extract what we want then make it pretty.
arrDN = split(strDN,",") 'CN=Example-Thing,CN=Whatever,CN=Etc
strDN = right(arrDN(0),len(arrDN(0))-3) 'CN=Example-Thing -> Example-Thing
strDN = replace(strDN,"-"," ") 'Example Thing
ParseDN = strDN
End Function

Function ParseMemberOf(memberof,primarygroupid)
'This shows what groups a person belongs to.
'The output of memberof changes depending on
'how many groups the user is a member of, etc.
Select Case TypeName(memberof)
Case "String" ParseMemberOf = ParseDN(memberof)
Case "Empty" ParseMemberOf = PrimaryGroupIDtoName(primarygroupid,varConfigNC)
Case "Variant()"
For each groupDN in memberof
strUserGroups = strUserGroups & vbCrLf & ParseDN(groupDN)
Next
ParseMemberOf = strUserGroups
Case Else ParseMemberOf = "Unknown"
End Select
End Function

Function SAMAccountTypetoName(theType)
'Just makin it more useful...
Select Case theType
Case 268435456 SAMAccountTypetoName = "Group Object"
Case 268435457 SAMAccountTypetoName = "Non-Security Group Object"
Case 536870912 SAMAccountTypetoName = "Alias Object"
Case 536870913 SAMAccountTypetoName = "Non-Security Alias Object"
Case 805306368 SAMAccountTypetoName = "Normal User Account"
Case 805306369 SAMAccountTypetoName = "Machine Account"
Case 805306370 SAMAccountTypetoName = "Trust Account"
Case 1073741824 SAMAccountTypetoName = "App Basic Group"
Case 1073741825 SAMAccountTypetoName = "App Query Group"
Case 2147483647 SAMAccountTypetoName = "Account Type Max"
Case Else SAMAccountTypetoName = "Unknown"
End Select
End Function

Function PrimaryGroupIDtoName(PGID,varConfigNC)
'Ugh.. the alternative to this function can be found here:
'http://support.microsoft.com/kb/297951
'both are kinda nasty.
Set objRSPGID = CreateObject("adodb.recordset")
Connstring = "Provider=ADsDSOObject"
strSQL = ";(objectCategory=group);distinguishedName,primaryGroupToken,name;subtree"
objRSPGID.Open strSQL, Connstring
If not objRSPGID.eof and not objRSPGID.bof Then
Do until objRSPGID.eof Or Len(strGroupName) > 0
If PGID = objRSPGID("primaryGroupToken") Then strGroupName = objRSPGID("name")
objRSPGID.movenext
Loop
End If
objRSPGID.close
Set objRSPGID = Nothing
If Len(strGroupName) = 0 Then strGroupName = "Unknown"
PrimaryGroupIDtoName = strGroupName
End Function

To schedule this, save the above code as ADAddedUsersNComputers.vbs in C:\scripts (for ex.) and use Scheduled Tasks to run the following command: %windir%\system32\wscript.exe C:\scripts\ADAddedUsersNComputers.vbs. I suggest running it daily at the end of each workday.

Some note:

1.

Thanks for the script. I ran into similar problems as Mohamed Ghaleb and fixed those by changing the below lines (Windows XP Pro box)

Function CompareDateUTCConvert(dateAddInterval,compareNumber)
'Wow, this is a lil complex. So createTimestamp is in UTC format.
'So first we grab your machine's time bias and then apply it.
'Next, we adjust the date to the one you specified above (now()-24hours by default)
'Finally, we parse the final date to UTC format ie. 20070207032200.0Z

Replaced line 91
'Set objSWbemServices = GetObject("winmgmts:\\" & "{impersonationLevel=impersonate}!\.\root\cimv2")

With:
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMIService = objSWBemlocator.ConnectServer(strComputer,"\root\CIMV2")

And line 94
' Set colTimeZone = objSWbemServices.ExecQuery("SELECT * FROM Win32_TimeZone")

With:
Set colTimeZone = objWMIService.ExecQuery("SELECT * FROM Win32_TimeZone")

The script now runs without a hitch. Now if I could only find out where to find how it was that added a user or computer.

Source:

http://blog.netnerds.net/2007/02/active-directory-newly-added-users-and-computers-notification-via-e-mail/#comments




0 comments:

Post a Comment

 
Toggle Footer
Top