Login | |
|
 |
Require assistance with script - 9/15/2005 3:52:06 AM
|
|
 |
|
| |
Bretai2k
Posts: 3
Score: 0
Joined: 9/15/2005
Status: offline
|
I have recently gotten into scripting and WMI, and by looking at example codes I was able to piece together a script that will call machine names from a text file, dump it into an array, collect hardware inventory data about each machine, and dump them into text files on my computer. The issue I am running into now is that any time the script comes across a machine that is not pinging on the network (either unknown host or no reply) the script dies. Could someone help me come up with a solution where the if the script cannot connect to the machine it will skip that machine and continue onto the next? I have looked everywhere and cannot find much about this specific issue. I have copied the script below and changed some of the system specific values. It was Frankensteined and tweaked from many different sources, so most of this code is not entirely my own. All help would be appreciated. TIA 'On Error Resume Next directive is specified so that users 'are not bothered by potential operational errors with the script. 'On Error Resume Next 'Using both of these flags of the WbemFlagEnum enumeration 'makes a semisynchronous WMI call. See "Making a Semisynchronous Call" 'in the WMI SDK for more information. Const wbemFlagReturnImmediately = 16 Const wbemFlagForwardOnly = 32 'WbemCimtypeEnum Enumerations used in the script Const wbemCimtypeUint32 = 19 Const wbemCimtypeSint64 = 20 Const wbemCimtypeUint64 = 21 'Formatting and number conversion constants Const HR = "----" Const KB = 1024 Const MB = 1048576 Const GB = 1073741824 'Change this to the UNC path where inventory files should be created 'Anyone running this script must have read and write access to the 'path. strInvFilePath = "location" 'Gathering the machine name data from the text file and 'place it into an array. On Error Resume Next 'Open the file system object Set oFSO = CreateObject("Scripting.FileSystemObject") set WSHShell = wscript.createObject("wscript.shell") 'Open the data file Set oTextStream = oFSO.OpenTextFile("text.txt") 'Make an array from the data file RemotePC = Split(oTextStream.ReadAll, vbNewLine) 'Close the data file oTextStream.Close For Each strComputer In RemotePC Set objWMIService = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") 'Determine the OS because not all classes listed here are supported 'on all versions of the Windows operating systems strProperties = "CreationClassName,Version,CSName,Caption" Set objOS = objWMIService.ExecQuery _ ("SELECT " & strProperties & " FROM Win32_OperatingSystem",_ ,wbemFlagReturnImmediately + wbemFlagForwardOnly) For Each Setting in objOS strCreationClass = Setting.CreationClassName intVersion = Setting.Version strCSName = Setting.CSName strCaption = Setting.Caption Next 'Check for a file named after the computer. If it doesn't 'exist, then create a file that contains the computer's 'hardware inventory. Set objFSO = CreateObject("Scripting.FileSystemObject") strFileName = "HrdWrInv_" & strCSName & ".txt" strFullName = objFSO.BuildPath(strInvFilePath, strFileName) If (objFSO.FileExists(strFullName)) Then WScript.Quit Set objFile = objFSO.CreateTextFile(strFullName) 'Write the Operating System name and version but nothing more. 'The goal is to collect hardware inventory, not software inventory 'and configuration information. objFile.WriteLine("OSInformation:") objFile.WriteLine("CreationClassName: " & strCreationClass) objFile.WriteLine("ComputerName: " & strCSName) objFile.WriteLine("Caption: " & strCaption) objFile.WriteLine("Version: " & intVersion) 'The name property is automatically returned (because it's a key value), so 'it's not absolutely necessary to specify it in strProperties strProperties = _ "CreationClassName,Manufacturer,Model,Name,NumberofProcessors," & _ "SystemType,TotalPhysicalMemory" QueryInstances "Win32_ComputerSystem",strProperties,"None" 'Page file information. strProperties = _ "Name,MaximumSize" QueryInstances "Win32_PageFileSetting",strProperties,"None" 'Physical memory information. 'Note, total memory is aggregated and listed with win32_computersystem so there's 'no need to query the memory classes, such as Win32_PhysicalMemoryArray or 'Win32_PhysicalMemory. However, if you need to find out how much memory 'a computer will hold, it's useful to query Win32_PhysicalMemoryArray as 'shown strProperties = _ "MaxCapacity,CreationClassName" QueryInstances "Win32_PhysicalMemoryArray",strProperties,"None" 'SCSI Disk controller information strProperties = _ "Name,Manufacturer,Description,CreationClassName" QueryInstances "Win32_SCSIController",strProperties,"None" 'IDE Disk controller information strProperties = _ "Name,Manufacturer,Description,CreationClassName" QueryInstances "Win32_IDEController",strProperties,"None" 'Phyiscal Media information 'Note, this class is only in XP (ver5) and the Windows 'Server 2003 family (ver5). 'Win98SE reports a version number of 4 (4.10.2222) If Mid(intVersion,1,3) >= 5.1 Then strProperties = _ "SerialNumber,CreationClassName" QueryInstances "Win32_PhysicalMedia",strProperties,"None" End If 'Logical Disk information strProperties = _ "DriveType,Description,DeviceID,CreationClassName" QueryInstances "Win32_LogicalDisk",strProperties,_ "DriveType!=3 AND DriveType !=4" 'Disk drive information strProperties = _ "Caption,Description,DeviceID,InterfaceType," & _ "Manufacturer,MediaType,Model,Partitions,Size,CreationClassName" QueryInstances "Win32_DiskDrive",strProperties,"None" 'Processor information strProperties = _ "Manufacturer,MaxClockSpeed,ExtClock,ProcessorType," & _ "Revision,Version,CreationClassName" QueryInstances "Win32_Processor",strProperties,"None" 'NIC information strProperties = _ "Manufacturer,MACAddress,ProductName,AdapterType,CreationClassName" QueryInstances "Win32_NetworkAdapter",strProperties,_ "AdapterType='Ethernet 802.3' AND ProductName !='Packet Scheduler Miniport'" 'Monitor information strProperties = _ "Description,MonitorType,CreationClassName" QueryInstances "Win32_DesktopMonitor",strProperties,"None" 'Video adapter information strProperties = _ "Name,MaxRefreshRate,AdapterRAM,CreationClassName" QueryInstances "Win32_VideoController",strProperties,"None" 'Motherboard information strProperties = _ "Description,Manufacturer,Product,CreationClassName" QueryInstances "Win32_BaseBoard",strProperties,"None" 'BIOS information strProperties = _ "Manufacturer, Name,SoftwareElementID,SMBIOSBIOSVersion," & _ "SMBIOSMajorVersion,SMBIOSMinorVersion,Version" QueryInstances "Win32_BIOS",strProperties,"None" objFile.Close Next MsgBox "Processing Done" '*****Subroutines and Functions********* Sub QueryInstances(objClass,Properties,Conditions) If Conditions = "None" Then strSelect = "Select " & Properties & " From " & objClass Else strSelect = "Select " & Properties & " From " & objClass & _ " Where " & Conditions End If Set objClassName = _ objWMIService.ExecQuery _ (strSelect,,wbemFlagReturnImmediately + wbemFlagForwardOnly) intCounter = 0 ' Can use the following to determine the # of items in the sWbemObjectSet but ' it's processor intensive and it means that you can't use a semi-synchronous ' call because the count property doesn't work with wbemFlagForwardOnly. ' WScript.Echo "# of items in collection: " & objClassName.Count For Each objComponent in objClassName If intCounter = 0 Then objFile.WriteLine(HR) objFile.WriteLine(Mid(objClass,7) & ":") End If For Each objProperty in objComponent.Properties_ 'Start by verifying that there's a value in the property. 'If not, it isn't necessary to perform the evaluation in this loop. If ISNull(objProperty.Value) Then objFile.WriteLine(objProperty.Name & ": Not available") Else If objProperty.CIMType <> wbemCimtypeUint32 And _ objProperty.CIMType <> wbemCimtypeUint64 And _ objProperty.CIMType <> wbemCimtypeSint64 Then objFile.WriteLine(objProperty.Name & ": " & _ objProperty.Value & " " & _ GetUnits(objClass,objProperty.Name)) Else strUnits = GetUnits(objClass,objProperty.Name) intValue = _ SizeFormat(objProperty.Name,objProperty.Value,strUnits) objFile.WriteLine(objProperty.Name & ": " & intValue) End If End If intCounter = intCounter + 1 Next If intCounter > 1 Then objFile.WriteLine(HR) Next objFile.WriteLine(HR) objFile.WriteLine() End Sub Function GetUnits(ClassName,ClassProperty) Set objSchemaClass = objWMIService.Get(ClassName) For Each objClassProperty in objSchemaClass.Properties_ If objClassProperty.Name = ClassProperty Then For Each objQualifier in objClassProperty.Qualifiers_ If LCase(objQualifier.Name) = "units" Then GetUnits = LCase(objQualifier.Value) End If Next End If Next End Function Function SizeFormat(PropertyName,RawValue,Units) Select Case LCase(Units) Case "bytes" If int(RawValue/GB) >= 1 Then SizeFormat = Round((RawValue/GB),1) & " gigabyte(s)" ElseIf int(RawValue/MB) >= 1 Then SizeFormat = int(RawValue/MB) & " megabyte(s)" Else SizeFormat = RawValue & " byte(s)" End If Case "kilobytes" If int(RawValue/MB) >= 1 Then SizeFormat = Round((RawValue/MB),1) & " gigabyte(s)" ElseIf int(RawValue/KB) >= 1 Then SizeFormat = int(RawValue/1024) & " megabyte(s)" Else SizeFormat = RawValue & " kilobyte(s)" End If Case Else SizeFormat = RawValue & " " & Units End Select End Function
|
|
| |
|
|
|
 |
RE: Require assistance with script - 9/15/2005 4:11:19 AM
|
|
 |
|
| |
ebgreen
Posts: 5069
Score: 31
Joined: 7/12/2005
Status: online
|
This is a common problem. There is the common solution and what is in my opinion the right solution. :) The common solution is to put the line 'On Error Resume Next' at the top of your script. THis essentially tells the script to ignore errors and keep on going. The right solution is to identify the specific line that is the problem. In you case I would sya that it is probably: Set objWMIService = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") Immediately before the problem line, put the line 'On Error Resume Next'. This is the only place that you should have that line (unless you have other calls that will be expected to fail). Immediately after the problem line, put some code like this: If Err.Number <> 0 Then bValidComputer = False 'If you want to, you can log the computers that were not available here. Else bValidComputer = True End If On Error Goto 0 Then you will need to wrap all the code that you only want to do for valid computers in an If - Then block like this: If bValidComputer Then 'Do your stuff here . . . . End If
|
|
| |
|
|
|
 |
RE: Require assistance with script - 9/15/2005 6:13:16 AM
|
|
 |
|
| |
ebgreen
Posts: 5069
Score: 31
Joined: 7/12/2005
Status: online
|
Here is what I would suggest doing (changes in red): 'Using both of these flags of the WbemFlagEnum enumeration 'makes a semisynchronous WMI call. See "Making a Semisynchronous Call" 'in the WMI SDK for more information. Const wbemFlagReturnImmediately = 16 Const wbemFlagForwardOnly = 32 'WbemCimtypeEnum Enumerations used in the script Const wbemCimtypeUint32 = 19 Const wbemCimtypeSint64 = 20 Const wbemCimtypeUint64 = 21 'Formatting and number conversion constants Const HR = "----" Const KB = 1024 Const MB = 1048576 Const GB = 1073741824 'Change this to the UNC path where inventory files should be created 'Anyone running this script must have read and write access to the 'path. strInvFilePath = "location" 'Gathering the machine name data from the text file and 'place it into an array. On Error Resume Next<--- REMOVE THIS 'Open the file system object Set oFSO = CreateObject("Scripting.FileSystemObject") set WSHShell = wscript.createObject("wscript.shell") 'Open the data file Set oTextStream = oFSO.OpenTextFile("text.txt") 'Make an array from the data file RemotePC = Split(oTextStream.ReadAll, vbNewLine) 'Close the data file oTextStream.Close For Each strComputer In RemotePC On Error Resume Next Set objWMIService = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") 'Determine the OS because not all classes listed here are supported 'on all versions of the Windows operating systems If Err.Number <> 0 Then bValidComputer = False 'If you want to log the machines that were not inventoried, do it here Else bValidComputer = True End If On Error Goto 0 If bValidComputer Then strProperties = "CreationClassName,Version,CSName,Caption" Set objOS = objWMIService.ExecQuery _ ("SELECT " & strProperties & " FROM Win32_OperatingSystem",_ ,wbemFlagReturnImmediately + wbemFlagForwardOnly) For Each Setting in objOS strCreationClass = Setting.CreationClassName intVersion = Setting.Version strCSName = Setting.CSName strCaption = Setting.Caption Next 'Check for a file named after the computer. If it doesn't 'exist, then create a file that contains the computer's 'hardware inventory. Set objFSO = CreateObject("Scripting.FileSystemObject") strFileName = "HrdWrInv_" & strCSName & ".txt" strFullName = objFSO.BuildPath(strInvFilePath, strFileName) If (objFSO.FileExists(strFullName)) Then WScript.Quit Set objFile = objFSO.CreateTextFile(strFullName) 'Write the Operating System name and version but nothing more. 'The goal is to collect hardware inventory, not software inventory 'and configuration information. objFile.WriteLine("OSInformation:") objFile.WriteLine("CreationClassName: " & strCreationClass) objFile.WriteLine("ComputerName: " & strCSName) objFile.WriteLine("Caption: " & strCaption) objFile.WriteLine("Version: " & intVersion) 'The name property is automatically returned (because it's a key value), so 'it's not absolutely necessary to specify it in strProperties strProperties = _ "CreationClassName,Manufacturer,Model,Name,NumberofProcessors," & _ "SystemType,TotalPhysicalMemory" QueryInstances "Win32_ComputerSystem",strProperties,"None" 'Page file information. strProperties = _ "Name,MaximumSize" QueryInstances "Win32_PageFileSetting",strProperties,"None" 'Physical memory information. 'Note, total memory is aggregated and listed with win32_computersystem so there's 'no need to query the memory classes, such as Win32_PhysicalMemoryArray Or 'Win32_PhysicalMemory. However, if you need to find out how much memory 'a computer will hold, it's useful to query Win32_PhysicalMemoryArray as 'shown strProperties = _ "MaxCapacity,CreationClassName" QueryInstances "Win32_PhysicalMemoryArray",strProperties,"None" 'SCSI Disk controller information strProperties = _ "Name,Manufacturer,Description,CreationClassName" QueryInstances "Win32_SCSIController",strProperties,"None" 'IDE Disk controller information strProperties = _ "Name,Manufacturer,Description,CreationClassName" QueryInstances "Win32_IDEController",strProperties,"None" 'Phyiscal Media information 'Note, this class is only in XP (ver5) and the Windows 'Server 2003 family (ver5). 'Win98SE reports a version number of 4 (4.10.2222) If Mid(intVersion,1,3) >= 5.1 Then strProperties = _ "SerialNumber,CreationClassName" QueryInstances "Win32_PhysicalMedia",strProperties,"None" End If 'Logical Disk information strProperties = _ "DriveType,Description,DeviceID,CreationClassName" QueryInstances "Win32_LogicalDisk",strProperties,_ "DriveType!=3 AND DriveType !=4" 'Disk drive information strProperties = _ "Caption,Description,DeviceID,InterfaceType," & _ "Manufacturer,MediaType,Model,Partitions,Size,CreationClassName" QueryInstances "Win32_DiskDrive",strProperties,"None" 'Processor information strProperties = _ "Manufacturer,MaxClockSpeed,ExtClock,ProcessorType," & _ "Revision,Version,CreationClassName" QueryInstances "Win32_Processor",strProperties,"None" 'NIC information strProperties = _ "Manufacturer,MACAddress,ProductName,AdapterType,CreationClassName" QueryInstances "Win32_NetworkAdapter",strProperties,_ "AdapterType='Ethernet 802.3' AND ProductName !='Packet Scheduler Miniport'" 'Monitor information strProperties = _ "Description,MonitorType,CreationClassName" QueryInstances "Win32_DesktopMonitor",strProperties,"None" 'Video adapter information strProperties = _ "Name,MaxRefreshRate,AdapterRAM,CreationClassName" QueryInstances "Win32_VideoController",strProperties,"None" 'Motherboard information strProperties = _ "Description,Manufacturer,Product,CreationClassName" QueryInstances "Win32_BaseBoard",strProperties,"None" 'BIOS information strProperties = _ "Manufacturer, Name,SoftwareElementID,SMBIOSBIOSVersion," & _ "SMBIOSMajorVersion,SMBIOSMinorVersion,Version" QueryInstances "Win32_BIOS",strProperties,"None" objFile.Close End If Next MsgBox "Processing Done" '*****Subroutines and Functions********* Sub QueryInstances(objClass,Properties,Conditions) If Conditions = "None" Then strSelect = "Select " & Properties & " From " & objClass Else strSelect = "Select " & Properties & " From " & objClass & _ " Where " & Conditions End If Set objClassName = _ objWMIService.ExecQuery _ (strSelect,,wbemFlagReturnImmediately + wbemFlagForwardOnly) intCounter = 0 ' Can use the following to determine the # of items in the sWbemObjectSet but ' it's processor intensive and it means that you can't use a semi-synchronous ' call because the count property doesn't work with wbemFlagForwardOnly. ' WScript.Echo "# of items in collection: " & objClassName.Count For Each objComponent in objClassName If intCounter = 0 Then objFile.WriteLine(HR) objFile.WriteLine(Mid(objClass,7) & ":") End If For Each objProperty in objComponent.Properties_ 'Start by verifying that there's a value in the property. 'If not, it isn't necessary to perform the evaluation in this loop. If ISNull(objProperty.Value) Then objFile.WriteLine(objProperty.Name & ": Not available") Else If objProperty.CIMType <> wbemCimtypeUint32 And _ objProperty.CIMType <> wbemCimtypeUint64 And _ objProperty.CIMType <> wbemCimtypeSint64 Then objFile.WriteLine(objProperty.Name & ": " & _ objProperty.Value & " " & _ GetUnits(objClass,objProperty.Name)) Else strUnits = GetUnits(objClass,objProperty.Name) intValue = _ SizeFormat(objProperty.Name,objProperty.Value,strUnits) objFile.WriteLine(objProperty.Name & ": " & intValue) End If End If intCounter = intCounter + 1 Next If intCounter > 1 Then objFile.WriteLine(HR) Next objFile.WriteLine(HR) objFile.WriteLine() End Sub Function GetUnits(ClassName,ClassProperty) Set objSchemaClass = objWMIService.Get(ClassName) For Each objClassProperty in objSchemaClass.Properties_ If objClassProperty.Name = ClassProperty Then For Each objQualifier in objClassProperty.Qualifiers_ If LCase(objQualifier.Name) = "units" Then GetUnits = LCase(objQualifier.Value) End If Next End If Next End Function Function SizeFormat(PropertyName,RawValue,Units) Select Case LCase(Units) Case "bytes" If int(RawValue/GB) >= 1 Then SizeFormat = Round((RawValue/GB),1) & " gigabyte(s)" ElseIf int(RawValue/MB) >= 1 Then SizeFormat = int(RawValue/MB) & " megabyte(s)" Else SizeFormat = RawValue & " byte(s)" End If Case "kilobytes" If int(RawValue/MB) >= 1 Then SizeFormat = Round((RawValue/MB),1) & " gigabyte(s)" ElseIf int(RawValue/KB) >= 1 Then SizeFormat = int(RawValue/1024) & " megabyte(s)" Else SizeFormat = RawValue & " kilobyte(s)" End If Case Else SizeFormat = RawValue & " " & Units End Select End Function I did not test this, but it should work barring silly things like typos. Speaking of which, once you get this working, you should consider investing the time in learning about 'Option Explicit' and using it.
|
|
| |
|
|
|
|
|