Script to fix duplicate SMS/SCCM GUID’s
I recently had an interesting issue come about with a grip of old school legacy machines scattered around several offices that contained identical disk images and SMS/SCCM agent GUID’s. The unintended consequences of this situation are computers improperly referenced in a collection plan. In addition machines were improperly re-imaged and applications inadvertently deployed. Our in-house solution was to create a script to parse a CSV (comma delimited) file including all machine names with duplicate GUID’s and run the following tasks:
1) Make sure machine is pingable
2) Stop SMS/SCCM Agent
3) Delete SMSCFG.ini
4) Start SMS/SCCM Agent to generate new SMSCFG.ini including GUID.
5) Report results to c:\FixSMSGUID_Results.csv
NOTE: Be sure you have sufficient rights on the destination machines before running this script!
'------------- START COPY ----------------'
'###########################################################################
'## VB Script: FixSMSGUID.vbs ##############################################
'## Purpose: Delete SMS.ini and restart SMS service. #######################
'## Author: shnizep atnospam gmail.com #####################################
'## Created: 2008-04-22 ####################################################
'## Last Modified: 2008-09-30 ##############################################
'###########################################################################
'## Changelog
On Error Resume Next
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
Const ForReading = 1
Const strOutputFile = "c:\FixSMSGUID_Results.csv"
'****************************************************************************
' Obtain CSV list of file.
'****************************************************************************
'Set objArgs = WScript.Arguments
'If objArgs.Count <> 0 Then
' Set str = WScript.Arguments.Item(1)
' Set intMode = WScript.Arguments.Item(2)
'ElseIf objArgs.Count = 0 Then
'Via browse dialog box if cmd line arguments null
MsgBox "Select duplicate GUID CSV"
Set objDialog = Createobject("Useraccounts.Commondialog")
objDialog.Filter = "Duplicate GUID CSV|*.csv"
'objDialog.Flags = &H0200
objDialog.Filterindex = 1
objDialog.InitialDir = "C:\"
'objDialog.dialogTitle = "Select a file"
intResult = objDialog.Showopen
If(intResult = 0) Then
Wscript.Echo "No duplicate GUID CSV file selected! Exiting.."
Wscript.quit
Else
strHostList = objDialog.FileName
End If
'****************************************************************************
'END CSV file.
'****************************************************************************
'****************************************************************************
Dim arrDupGUID(1)
Dim i, sleepDur, intSleep, strService, objService, errReturn, strMsg
intSleep = 10000
sleepDur = 0
intSleepRetry = 1000
strService = "ccmexec"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
(strHostList, ForReading)
Wscript.echo "Removing duplicate GUID's...."
Wscript.echo
'Create Fix SMS GUID status CSV
If objFSO.FileExists(strOutputFile) Then
objFSO.DeleteFile(strOutputFile)
End If
Set objOutputFile = objFSO.CreateTextFile(strOutputFile, True)
'Loop through each line of file
Do Until objTextFile.AtEndOfStream
strNextLine = objTextFile.Readline
i = 0
For Each strItem In CSVParse(strNextLine)
arrDupGUID(i) = strItem
i = i + 1
Next
strHost = arrDupGUID(0)
strStatus = arrDupGUID(1)
Wscript.Echo "Hostname: "& strHost
'Wscript.echo "Machines status: "& strStatus
'If machines GUID has not already been fixed.
If strStatus = "Done" Then
Wscript.echo "Host already done, skipping: "& strHost
strMsg = "Done"
Wscript.echo
Else
If fctIsAlive(strHost) = False Then
strMsg = "Ping timeout"
Wscript.echo strMsg
Wscript.echo
Else
If Len(strHost) = 0 Then
Wscript.echo "Hostname string is null, check your IMPORT file!...Exiting..."
Wscript.quit
End If
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strHost)
If Err.Number Then
'Wscript.Echo Err.Number
Wscript.Echo "Error: "& Err.Description
'Wscript.Echo "Could not connect to the WMI Service"
Wscript.Echo
strMsg = Err.Description
Else
Set objService = objWMIService.Get("Win32_Service.Name='" & strService & "'")
'Get Windows Directory
Set objOS = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
For Each colOS In objOS
strWindowsDir = colOS.WindowsDirectory
Next
'Wscript.Echo "Windows Dir: "& strWindowsDir
Set objIniDel = GetObject("winMgmts:CIM_DataFile.Name='" & strWindowsDir & "\SMSCFG.INI'")
'##########################################################
'Stop the service, delete SMSCFG.INI and start the service.
'##########################################################
'Stop SMS Host Agent Service
Wscript.Echo "Stopping SMS Agent Host service"
errReturn = objService.StopService()
If errReturn <> 0 Then
'Wscript.Echo "Error: " & errReturn
strMsg = errReturn.Description
Wscript.Echo strMsg
End If
Wscript.Echo "Waiting..."
'Wscript.Echo "State: "& objService.State
Wscript.Sleep intSleep
strState = objService.State
'Make sure service is stopped before continuing
Do Until strState = "Stopped"
Wscript.Echo "Service still stopping, waiting..."
Wscript.Sleep intSleepRetry
Set objState = objWMIService.Get("Win32_Service.Name='" & strService & "'")
strState = objState.State
sleepDur = sleepDur + 1
If sleepDur = 30 Then
strMsg = "Timeout Could not stop SMS Agent service"
strState = "Stopped"
End If
'Wscript.Echo "State: "& strState
Loop
'Delete SMSCFG.ini file
Wscript.Echo "Deleting SMSCFG.ini file"
errReturn = objIniDel.delete
If errReturn <> 0 Then
'Wscript.Echo "Error: " & errReturn
Wscript.Echo "Could not delete SMSCFG.ini file"
strMsg = "Could not delete SMSCFG.ini file"
End If
'Start SMS Host Agent Service
Wscript.Echo "Starting SMS Agent Host service"
errReturn = objService.StartService()
If errReturn <> 0 Then
'Wscript.Echo "Error: " & errReturn
Wscript.Echo "Service could not start"
End If
'Reset sleep duration
sleepDur = 0
'Make sure service is started before continuing
Do Until strState = "Running"
Wscript.Echo "Service still starting, waiting..."
Wscript.Sleep intSleepRetry
Set objState = objWMIService.Get("Win32_Service.Name='" & strService & "'")
strState = objState.State
'Wscript.Echo "State: "& strState
sleepDur = sleepDur + 1
If sleepDur = 30 Then
strMsg = "Timeout Could not Start SMS Agent service"
strState = "Running"
End If
Loop
Wscript.echo "SMS Host Service is Running"
'Wscript.echo "Done with: "& strHost
If Len(StrMsg) = 0 Then
strMsg = "Done"
End If
Wscript.echo
End If 'END If cannot connect
End If ' If cannot ping
End If 'END If machines GUID has not already been fixed.
Err.Clear
objOutputFile.Writeline strHost & ","& strMsg
StrMsg = ""
Loop 'END - Loop through line of file
'END - Reading CSV
'Close file for Writing
objOutputFile.Close
Wscript.quit
Function fctIsAlive(strHostOrIP)
'Function to make sure machine is pingable.
'Stolen from http://www.fpschultze.de/uploads/wmiping.vbs.txt
Dim objSh, objCmd, strCmd
strCmd = "%ComSpec% /C %SystemRoot%\system32\ping.exe -n 1 " & strHostOrIP & " | " _
& "%SystemRoot%\system32\find.exe /c /i " & Chr(34) & "ttl=" & Chr(34)
Set objSh = WScript.CreateObject("WScript.Shell")
Set objCmd = objSh.Exec(strCmd)
fctIsAlive = CBool(Trim(objCmd.StdOut.ReadAll))
Set objCmd = Nothing
Set objSh = Nothing
End Function
Function CSVParse(ByVal strLine)
' Function to parse comma delimited line and return array
' of field values.
' Stolen from http://www.rlmueller.net/Programs/ReadCSV.txt
Dim arrFields
Dim blnIgnore
Dim intFieldCount
Dim intCursor
Dim intStart
Dim strChar
Dim strValue
Const QUOTE = """"
Const QUOTE2 = """"""
' Check for empty string and return empty array.
If (Len(Trim(strLine)) = 0) then
CSVParse = Array()
Exit Function
End If
' Initialize.
blnIgnore = False
intFieldCount = 0
intStart = 1
arrFields = Array()
' Add "," to delimit the last field.
strLine = strLine & ","
' Walk the string.
For intCursor = 1 To Len(strLine)
' Get a character.
strChar = Mid(strLine, intCursor, 1)
Select Case strChar
Case QUOTE
' Toggle the ignore flag.
blnIgnore = Not blnIgnore
Case ","
If Not blnIgnore Then
' Add element to the array.
ReDim Preserve arrFields(intFieldCount)
' Makes sure the "field" has a non-zero length.
If (intCursor - intStart > 0) Then
' Extract the field value.
strValue = Mid(strLine, intStart, _
intCursor - intStart)
' If it's a quoted string, use Mid to
' remove outer quotes and replace inner
' doubled quotes with single.
If (Left(strValue, 1) = QUOTE) Then
arrFields(intFieldCount) = _
Replace(Mid(strValue, 2, _
Len(strValue) - 2), QUOTE2, QUOTE)
Else
arrFields(intFieldCount) = strValue
End If
Else
' An empty field is an empty array element.
arrFields(intFieldCount) = Empty
End If
' increment for next field.
intFieldCount = intFieldCount + 1
intStart = intCursor + 1
End If
End Select
Next
' Return the array.
CSVParse = arrFields
End Function
'------------- END COPY ------------------'
Please note that an alternative solution might be found within a Microsoft Technet SMSANDMOM blog entry I recently happened upon.
MY NORMAL DISCLAIMER APPLIES: Although I have used this script with success in my environment, every environment varies. You run this script at your own risk blogmynog.com and associates are in no way responsible for damages incurred running any provided scripts on blogmynog.com or associated websites. Be sure to test this in a non-production environment first before using it in production.





Reader Comments
Have you tried running cscript c:\script.vbs in the command prompt?