Link to home
Start Free TrialLog in
Avatar of damoncf1234
damoncf1234

asked on

vb script doesn't run completely

Hello,

I have a script that runs on our (2003) domain that basically attempts to ping each computer in active directory, then writes a text file that contains information such as the last logged-on username, IP address, MAC, memory, machine type, virus definition dates, etc...  It also verifies the local admin account is named appropriately and has the correct password.  It then e-mails the created .csv file to whoever we specify at the bottom of the script.  

It was running successfully daily for about a month, with a file size of about 200k.  Lately it stops running after only 8 or so computers, with a file size of about 6k.  

I'm wondering if there's some sort of error in the script that's causing it to "stop" after about 8 machines, rather than scanning the rest of the machines in the domain as it did previously.  

Any help would be appreciated.  Thanks.  
-Chris
On Error Resume Next
 
Const ADS_SCOPE_SUBTREE = 2
Const ForWriting = 2
Const ForReading = 1
Const HKEY_LOCAL_MACHINE = &H80000002
Const OpenAsDefault = -2
Const FailIfNotExist = 0
 
strDay = Day(NOW)
	If strDay < 10 Then strDay = "0" & strDay
strMonth = MonthName((Month(NOW)),True)
strYear = Year(NOW)
strDate = strDay & strMonth & strYear
 
Set objFSO = CreateObject("Scripting.FileSystemObject")
set objShell = CreateObject("Wscript.Shell")
strScriptPath = objFSO.GetParentFolderName(wScript.ScriptFullName)
 
Set objLogFile = objFSO.CreateTextFile("Inventory_" & strDate & ".csv", ForWriting, True)
 
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingConteXt")
 
'Binds to Active Directory
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open = "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
 
objCommand.Properties("Page Size") = 1000
objCommand.Properties("SearchScope") = ADS_SCOPE_SUBTREE
 
objLogFile.WriteLine "MachineName	IP_Address	Vendor	Model	Service_Tag	User	Processor	Speed	MacAddress	Memory	DiskSize	Freespace	VirusDefDate"
 
'Searches for all computers in the domain
objCommand.CommandText = "SELECT Name FROM 'LDAP://" & strDNSDomain & "' WHERE objectCategory='computer'"
Set objRecordset = objCommand.Execute
 
objRecordSet.MoveFirst
 
Do Until objRecordSet.EOF
	strComputer = objRecordSet.Fields("Name").value
 
	strCommand = "%comspec% /c ping -n 3 -w 1000 " & strComputer & ""
	Set objExecObject = objShell.Exec(strCommand)
 
	Do While Not objExecObject.StdOut.AtEndOfStream
	strText = objExecObject.StdOut.ReadAll()
		If Instr(strText, "Reply") > 0 Then
		arrPingReply = Split(strText," ")
		strIP = Replace(arrPingReply(14),":","")
 
 
			'Determine Model Number, Service Tag
			Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strIP & "\root\cimv2")
			If objWMIService IS Nothing Then
			objLogFile.Writeline strComputer & vbtab & "unable_to_connect_to_WMI!"
			Else
 
				Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystemProduct")
					For Each objItem In colItems
					strModel = objItem.Name
					strVendor = objItem.Vendor
					strServiceTag = objItem.IdentifyingNumber
					Next
 
				Set colProcessors = objWMIService.ExecQuery("Select * from Win32_Processor")
					For Each objProcessor in colProcessors
					strProcessor = objProcessor.Name
					strClockSpeed = objProcessor.MaxClockSpeed
					Next
 
 
				Set colNetworkCards = objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration Where IPEnabled=True")
					For Each objNetworkCard In colNetworkCards
					strMacAddress = objNetworkCard.MacAddress
					Next
 
				Set colMemory = objWMIService.ExecQuery("Select * from Win32_PhysicalMemory")
					For Each objMemory In colMemory
					strMemory = Round(objMemory.Capacity/1048576)
					Next
 
				Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk Where DriveType = '3'")
					For Each objDisk In colDisks
					strDiskSize = Round(objDisk.Size/1073741824)
					strFreeSpace = Round(objDisk.Freespace/1073741824)
					Next
 
				'Rename the local admin account and set it's password to default
				If Instr(strComputer,"-DC") = 0 Then
				Set colAccounts = objWMIService.ExecQuery("Select * From Win32_UserAccount Where LocalAccount = TRUE")
					For Each objAccount in colAccounts
						If Left (objAccount.SID, 6) = "S-1-5-" and Right(objAccount.SID, 4) = "-500" Then
					        	Set objAdmin = GetObject("WinNT://" & objAccount.Domain & "/" & objAccount.Name)
							objAdmin.SetPassword("password")
							objUser.Rename("username")
						End If
					Next
				
				'Determine last logged on user
				Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
				strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\WinLogon"
				strValueName = "DefaultUserName"
				objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strLastLoggedOnUser
				
				Else
 
				strLastLoggedOnUser = "SysAdmin"
 
				End If
			
				If objFSO.FileExists("\\" & strIP & "\c$\Program Files\Common Files\Symantec Shared\VirusDefs\definfo.dat") Then
      					Set objFile = objFSO.OpenTextFile("\\" & strIP & "\c$\Program Files\Common Files\Symantec Shared\VirusDefs\definfo.dat", ForReading, FailIfNotExist, OpenAsDefault)
				Else
					stVirusDefDate = 0
				End If
				strResults = objFile.ReadAll
				objFile.Close
    
  				arrSplitAtCurDefs = Split(strResults, "CurDefs=")
				arrSplitAtLF = Split(arrSplitAtCurDefs(1), vbLf)
				strVirusDefDate = Replace(arrSplitAtLF(0), vbCr, "")
	
				objLogFile.WriteLine strComputer & vbtab & strIP & vbtab & strVendor & vbtab & strModel & vbtab & strServiceTag & vbtab & strLastLoggedOnUser & vbtab & strProcessor & vbtab & strClockSpeed & vbtab & strMacAddress & vbtab & strMemory & vbtab & strDiskSize & vbtab & strFreeSpace & vbtab & strVirusDefDate
		
			End If
 
		Else
		'Unable to connect to machine
		'objLogFile.WriteLine strComputer & vbtab & "not_pingable!"
		End If
	Loop
 
	objRecordSet.MoveNext
 
Set objWMIService = Nothing
strLastLoggedOnUser = "Unknown"
 
Loop
 
objLogFile.Close
 
'Now we send this csv file as an attachment to somebody that cares
Set objemail = CreateObject("CDO.Message")
objEmail.From = "user@domain.com"
objEmail.To = "user@domain.com"
objEmail.CC = "user2@domain.com"
objEmail.subject = "Inventory Report for" & strDate
objEmail.TextBody = "This email and the attached inventory file was created by a script.  It is repeatable and if something needs changed, let me know."
objEmail.AddAttachment(strScriptPath & "\Inventory_" & strDate & ".csv")
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "192.168.48.4"
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objEmail.Configuration.Fields.Update
objEmail.Send

Open in new window

Avatar of flob9
flob9
Flag of France image

Can you comment the line "On Error Resume Next" then launch the script manually ?
Avatar of damoncf1234
damoncf1234

ASKER

flob9,
I commented out the "On Error Resume Next" and launched the script as you suggested.  Long story short, a few errors came up, and I worked through them.  I got the script to work on one network fine -- all of the machines come up as expected, with all fileds populated.  Also, a black command window comes up and disappears for each workstation found in AD.  

Now the problem is that this script works perfectly on one of our networks, but on another (isolated) network, it runs until the .csv file reaches 6kb, and stops (the black command windows stop appearing as well).  We've tried running it from different machines, including the domain controllers, with the same results.  On this particular network, the script runs fine until the .csv file reaches 6 kb and then stops...  

Do you have any suggestions as to why this could be happening on one network, even though the script runs fine on another network?  I'm wondering if there's a bad computer account in AD on the second network that is causing the script to stop at the same point each time, which happens to be when the .csv file is at 6kb...?  Any ideas?  

Is there a way to modify this script to have it run in a specific OU?  Or could we specify a list of machine names to run from, instead of pulling a list from AD?  Any help would be appreciated.  

Below is the modified version of the script that works on one network, but stops after 6kb on the second.  
On Error Resume Next
 
Const ADS_SCOPE_SUBTREE = 2
Const ForWriting = 2
Const ForReading = 1
Const HKEY_LOCAL_MACHINE = &H80000002
Const OpenAsDefault = -2
Const FailIfNotExist = 0
 
strDay = Day(NOW)
	If strDay < 10 Then strDay = "0" & strDay
strMonth = MonthName((Month(NOW)),True)
strYear = Year(NOW)
strDate = strDay & strMonth & strYear
 
Set objFSO = CreateObject("Scripting.FileSystemObject")
set objShell = CreateObject("Wscript.Shell")
strScriptPath = objFSO.GetParentFolderName(wScript.ScriptFullName)
 
Set objLogFile = objFSO.CreateTextFile("Inventory_" & strDate & ".csv", ForWriting, True)
 
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingConteXt")
 
'Binds to Active Directory
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open = "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
 
objCommand.Properties("Page Size") = 1000
objCommand.Properties("SearchScope") = ADS_SCOPE_SUBTREE
 
objLogFile.WriteLine "MachineName	IP_Address	Vendor	Model	Service_Tag	User	Processor	Speed	MacAddress	Memory	DiskSize	Freespace	VirusDefDate"
 
'Searches for all computers in the domain
objCommand.CommandText = "SELECT Name FROM 'LDAP://" & strDNSDomain & "' WHERE objectCategory='computer'"
Set objRecordset = objCommand.Execute
 
objRecordSet.MoveFirst
 
Do Until objRecordSet.EOF
	strComputer = objRecordSet.Fields("Name").value
 
	strCommand = "%comspec% /c ping -n 3 -w 1000 " & strComputer & ""
	Set objExecObject = objShell.Exec(strCommand)
 
	Do While Not objExecObject.StdOut.AtEndOfStream
	strText = objExecObject.StdOut.ReadAll()
		If Instr(strText, "Reply") > 0 Then
		arrPingReply = Split(strText," ")
		strIP = Replace(arrPingReply(14),":","")
 
 
			'Determine Model Number, Service Tag
			Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strIP & "\root\cimv2")
			If objWMIService IS Nothing Then
			objLogFile.Writeline strComputer & vbtab & "unable_to_connect_to_WMI!"
			Else
 
				Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystemProduct")
					For Each objItem In colItems
					strModel = objItem.Name
					strVendor = objItem.Vendor
					strServiceTag = objItem.IdentifyingNumber
					Next
 
				Set colProcessors = objWMIService.ExecQuery("Select * from Win32_Processor")
					For Each objProcessor in colProcessors
					strProcessor = objProcessor.Name
					strClockSpeed = objProcessor.MaxClockSpeed
					Next
 
 
				Set colNetworkCards = objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration Where IPEnabled=True")
					For Each objNetworkCard In colNetworkCards
					strMacAddress = objNetworkCard.MacAddress
					Next
 
				Set colMemory = objWMIService.ExecQuery("Select * from Win32_PhysicalMemory")
					For Each objMemory In colMemory
					strMemory = Round(objMemory.Capacity/1048576)
					Next
 
				Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk Where DriveType = '3'")
					For Each objDisk In colDisks
					strDiskSize = Round(objDisk.Size/1073741824)
					strFreeSpace = Round(objDisk.Freespace/1073741824)
					Next
 
'Determine last logged on user
				Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
				strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\WinLogon"
				strValueName = "DefaultUserName"
				objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strLastLoggedOnUser
				
				'Else
 
				'strLastLoggedOnUser = "SysAdmin"
 
				'End If
 
If objFSO.FileExists("\\" & strIP & "\c$\Program Files\Common Files\Symantec Shared\VirusDefs\definfo.dat") Then
      					Set objFile = objFSO.OpenTextFile("\\" & strIP & "\c$\Program Files\Common Files\Symantec Shared\VirusDefs\definfo.dat", ForReading, FailIfNotExist, OpenAsDefault)
				Else
					stVirusDefDate = 0
				End If
				strResults = objFile.ReadAll
				objFile.Close
    
  				arrSplitAtCurDefs = Split(strResults, "CurDefs=")
				arrSplitAtLF = Split(arrSplitAtCurDefs(1), vbLf)
				strVirusDefDate = Replace(arrSplitAtLF(0), vbCr, "")
	
				objLogFile.WriteLine strComputer & vbtab & strIP & vbtab & strVendor & vbtab & strModel & vbtab & strServiceTag & vbtab & strLastLoggedOnUser & vbtab & strProcessor & vbtab & strClockSpeed & vbtab & strMacAddress & vbtab & strMemory & vbtab & strDiskSize & vbtab & strFreeSpace & vbtab & strVirusDefDate
		
			End If
 
		Else
		'Unable to connect to machine
		'objLogFile.WriteLine strComputer & vbtab & "not_pingable!"
		End If
	Loop
 
	objRecordSet.MoveNext
 
Set objWMIService = Nothing
strLastLoggedOnUser = "Unknown"
 
Loop
 
objLogFile.Close

Open in new window

I reckon that the 6k thing just happens to be 6k because that is how much data has been collected before the script encounters a machine that it has a problem with.  For whatever reason this machine makes the script barf.
Can you take the On Error Resume Next out again and see what error you get.
From experience, WMI is your most likely problem but if you can get the line that is causing the exception, we can probably handle the error in a nicer way.
 
ASKER CERTIFIED SOLUTION
Avatar of flob9
flob9
Flag of France image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Alan,
That's what I was thinking about the 6kb thing as well, that it must be some machine that's messing the script up, and is just a coincidence that the .csv file is always 6kb when it happens.  

Flob9,

About the second network, we're sure that there are missing computers.  There are over 1000 machines on the second network, and when the script stops the .csv file only contains about 8 machines...  

I'm at a remote site today and don't have access to the second network, but I'll take out the "on error resume next" and add the WScript.echo "Working on " & strComputer and let you know what the results are.  

Thanks.
Is there a way to run this script on a specific OU, rather all computer accounts in AD?  I'm thinking that might help isolate groups of machines, and help determine if there are "problem machines" that are causing the script to stop...  
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Alan/flob9,

Thanks for the response.  I added the wscript.echo strComputer into the script, and also added the line to run the script in a specific OU.  The first 3 OUs went fine, bringing up a box with each machine name.  We're able to get the .csv file to go well above 6k now as it scans each OU individually.  Some machines are coming up as "unable to connect to WMI.  What would be causing this?  I'm running the script as a domain admin, so I should have the appropriate rights.  

Another "difference" I've seen between the script running on the first network (the one that has always worked without any issues) and the second network (the one that stops running) is the command prompt (black) windows don't popup on the 1st network, but they do on the second network...  What would cause this?