I cobbled together a script to install the Microsoft SCCM client to a group of PCs, and it works most of the time. I'm trying to figure out why it doesn't work the rest of the time and if there's different code I could use or if there's some error handling I could add to prevent the script from exiting prematurely.

Here's the basic mechanics of the script: it reads a text file containing a list of PC names. It checks the local PC to make sure it has the executable files that will need to be copied to the remote PC. It checks the remote PC registry to determine whether the PC already has the SCCM client, the older SMS client, or neither. If the remote PC has the SCCM client, no action is taken. If it has the older SMS client or neither client, the appropriate exe is copied to the remote PC and is then triggered to run.

Sometimes the script bombs at this line:
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & CompName & "\root\default:StdRegProv")

One of two errors are thrown: "The remote server machine does not exist or is unavailable" or "Permission denied: GetObject".

And sometimes the script bombs at this line:
objReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

The error thrown is: The handle is invalid. Source: SWbemObjectEx.

At first I took the lazy way and added the line "On Error Resume Next", figuring that would skip past the errors, and I could deal with the machines throwing the errors on an individual basis. But that only caused the script to exit prematurely.

Then I removed the "On Error Resume Next" line and tried adding some error handling around the problem lines, but so far I haven't been able to get that working, either. The script errors out when it hits one of the lines noted above and ignores any error handling I've tried to add.

Here's the script in its entirety. There are more comments than are probably needed for the average coder; I added them in so the person receiving the script could understand what the script was doing, as they are in the process of learning VB scripting.

Option Explicit
Dim fName, strCompName
Dim objFSO, objFSO1, objFSO2, objReg, objLog, objFile, objPing
Dim bSCCM_setup, bSMS_ext, bSCCM, bSmsextFileExists, bCcsetupFileExists
Dim StdOut
Dim strKeyPath, strValueName, strValue, intRet, strFileName, strSCCM_Version
Dim TraceResult, Addresses
'On Error Resume Next
' set constant to path of exe's
Const SCCM_EXE_LOCAL = "C:\Windows\system32\ccmsetup\ccmsetup.exe"
Const SMSEXT_EXE_LOCAL = "C:\Windows\system32\ccmsetup\smsext.exe"
' constants for the Scheduled Job we'll trigger to do the install on the remote PC
Const INTERVAL = "n"
Const MINUTES = 1
' constant for use with querying registry on remote PC
Const HKEY_LOCAL_MACHINE = &H80000002
' allows us to read from txt file list of PCs
Const ForReading = 1
'set constant for writing to a log file
Const ForWriting = 8
' name & location of log file
' ASSUMES LOG FILE WILL BE NAMED AND LOCATED ACCORDING TO
' NEXT LINE OF CODE. CHANGE THE FILENAME AND/OR PATH AS NEEDED.
strFileName = "C:\SCCM_Results.log"
' create object representing log file; open it for writing
Set objFSO1 = CreateObject("Scripting.FileSystemObject")
Set objLog = objFSO1. OpenTextFile(strFileName, ForWriting, True)
' create object representing the text file
Set objFSO2 = CreateObject("Scripting.FileSystemObject")
' now open that text file
' ASSUMES TEXT FILE OF PC IDs WILL BE NAMED AND LOCATED ACCORDING TO
' NEXT LINE OF CODE. CHANGE THE FILENAME AND/OR PATH AS NEEDED.
Set objFile = objFSO2.OpenTextFile("C:\RemoteInstallScripts\PC_list.txt")

' CALL TO ROUTINE THAT READS EACH PC NAME
ReadPCname ' read name of each PC from PC_list.txt

' **************
' SUB-ROUTINES
' **************
Sub ReadPCname()
' read through text file until the end
Do Until objFile.AtEndOfStream
' read each line of the text file, one line at a time
strCompName = objFile.ReadLine
ClientCheck ' check if remote PC can be pinged, then
' check local PC for necessary exe's;
' check if local PC has SCCM client, SMS client, or no client,
' and install accordingly

Loop
End Sub

Sub ClientCheck()
' confirm that remote PC can be pinged
Set objPing = GetObject("winmgmts://PAE801/root/default:PingPoller")
'WSCript.Echo "Made it past ping poller."
objPing.Trace strCompName, "30", "1000", "1", TraceResult, Addresses
WScript.Echo TraceResult
If TraceResult <> 0 Then
objLog.WriteLine strCompName & vbTab & "Did not respond to ping."
Else
' Check if remote PC already has SCCM installed
strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{CE6A85D8-D6B9-479A-9FE9-A06E56881E61}"
strValueName = "DisplayName"
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strCompName & "\root\default:StdRegProv")
objReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
If strValue = "Configuration Manager Client" Then
' remote PC has SCCM client
bSCCM = 1 ' SCCM installed
objLog.WriteLine strCompName & vbTab & "has SCCM client installed."
Exit Sub
'WScript.Quit
End If
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(SCCM_EXE_LOCAL) Then
' now check if the EXE version indicates SCCM rather than the SMS client (4.0.6221.1000 is SCCM)
strSCCM_Version = objFSO.GetFileVersion(SCCM_EXE_LOCAL)
If strSCCM_Version <> "4.0.6221.1000" Then
bSCCM_setup = 0 ' 0 means SCCM exe does NOT reside on local PC
Else
bSCCM_setup = 1 ' 1 means SCCM exe resides on local PC
End If
Else
bSCCM_setup = 0 ' 0 means SCCM exe does NOT reside on local PC
End If
If objFSO.FileExists(SMSEXT_EXE_LOCAL) Then
bSMS_ext = 1 ' 1 means smsext.exe resides on local PC
Else
bSMS_ext = 0 ' 0 means smsext.exe does NOT reside on local PC
End If
If bSCCM_setup = 0 And bSMS_ext = 0 Then
MsgBox "Required files (ccmsetup.exe v4.0.6221.1000 and smsext.exe) missing from local PC." & vbCrLf _
& "Please copy the required files before continuing.", 1, "Files Missing"
Exit Sub
'WScript.Quit
ElseIf bSCCM_setup = 0 And bSMS_ext <> 0 Then
MsgBox "ccmsetup.exe (v4.0.6221.1000) missing from local PC." & vbCrLf _
& "Please copy the file locally before continuing.", 1, "File Missing"
Exit Sub
'WScript.Quit
ElseIf bSCCM_setup <> 0 And bSMS_ext = 0 Then
MsgBox "smsext.exe missing from local PC." & vbCrLf _
& "Please copy the file locally before continuing.", 1, "File Missing"
Exit Sub
'WScript.Quit
End If
' THIS IS FOR SMSEXT.EXE
' check if remote PC has SCCM client, SMS client, or neither.
' copy the appropriate file to the remote PC and install it.
bSCCM = 0 'set boolean to indicate SCCM is not installed
strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{83AD5E71-80C0-4818-B6E4-CA2607B6A141}"
strValueName = "DisplayName"
objReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
If strValue = "SMS Advanced Client" Then ' remote PC has SMS client
' copy smsext.exe to remote PC (removes SMS, installs SCCM)
objFSO.CopyFile SMSEXT_EXE_LOCAL, "\\" & strCompName & "\C$\Windows\Temp\"
' install smsext.exe on remote PC, which uninstalls SMS and then installs the SCCM client
strCommand = "\\" & strCompName & "\C$\Windows\Temp\ccmsetup.exe"
Set objWMIService = GetObject("winmgmts:\\" & strCompName & "\root\cimv2")
Set objScheduledJob = objWMIService.Get("Win32_ScheduledJob")
Set objSWbemDateTime = CreateObject("WbemScripting.SWbemDateTime")
objSWbemDateTime.SetVarDate(DateAdd(INTERVAL, MINUTES, Now()))
errReturn = objScheduledJob.Create(strCommand, objSWbemDateTime.Value, False, 0, 0, True, intJobID)
If errReturn = 0 Then
objLog.WriteLine strCompName & vbTab & "smsext.exe starting in 1 minute."
Else
objLog.WriteLine strCompName & vbTab & "ERROR. smsext.exe could not be started."
End If
bSCCM = 1 ' SCCM installed
End If
' THIS IS FOR CCMSETUP.EXE
' If neither of the above cases meet the conditions, then remote PC has neither SMS nor SCCM,
' so install SCCM client.
If bSCCM = 0 Then
objFSO.CopyFile SCCM_EXE_LOCAL, "\\" & strCompName & "\C$\Windows\Temp\"
' run ccmsetup.exe on remote PC
' install the SCCM client on the remote PC
strCommand = "\\" & strCompName & "\C$\Windows\Temp\ccmsetup.exe SMSSITECODE=AUTO"
Set objWMIService = GetObject("winmgmts:\\" & strCompName & "\root\cimv2")
Set objScheduledJob = objWMIService.Get("Win32_ScheduledJob")
Set objSWbemDateTime = CreateObject("WbemScripting.SWbemDateTime")
objSWbemDateTime.SetVarDate(DateAdd(INTERVAL, MINUTES, Now()))
errReturn = objScheduledJob.Create(strCommand, objSWbemDateTime.Value, False, 0, 0, True, intJobID)
If errReturn = 0 Then
objLog.WriteLine strCompName & vbTab & "ccmsetup.exe installation starting in 1 minute."
Else
objLog.WriteLine strCompName & vbTab & "ERROR. ccmsetup.exe could not be started."
End If
End If
End If
End Sub

MsgBox "Done!",,"DONE!"

0 Comments   [ + ] Show Comments

Comments

Please log in to comment

Rating comments in this legacy AppDeploy message board thread won't reorder them,
so that the conversation will remain readable.

Answers

0
- Add the 'On Error Resume Next' line
- Install the MS Script Debugger (MSD) or, better, the Microsoft Script Editor (MSE)
- Add the line 'If Err.Number <> 0 Then Stop' immediately after the line which creates the registry object and after the line which uses its GetStringValue method
- Run the script

It will halt execution at the first error and either load the script with the erroring line highlighted (MSD) or prompt you to start MSE, then a dialog with an OK button, finally doing more or less the same as MSD.

MSE will show variable content in tooltips if you hover over them. MSD will require you to use the 'Immediate' window to "Print strValue" (or, in shorthand, "? strvalue").

I suspect that you simply need to handle missing keys and/or value names.

Finally, I'd suggest getting hold of the JSWare Registry class file and using that instead of your own routines. It has reasonable error-handling already, returning integers to the calling code for success or failure.
Answered 11/10/2009 by: VBScab
Red Belt

Please log in to comment
Answer this question or Comment on this question for clarity